dom/plugins/test/testplugin/nptest.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* ***** BEGIN LICENSE BLOCK *****
     2  *
     3  * Copyright (c) 2008, Mozilla Corporation
     4  * All rights reserved.
     5  *
     6  * Redistribution and use in source and binary forms, with or without
     7  * modification, are permitted provided that the following conditions are met:
     8  *
     9  * * Redistributions of source code must retain the above copyright notice, this
    10  *   list of conditions and the following disclaimer.
    11  * * Redistributions in binary form must reproduce the above copyright notice,
    12  *   this list of conditions and the following disclaimer in the documentation
    13  *   and/or other materials provided with the distribution.
    14  * * Neither the name of the Mozilla Corporation nor the names of its
    15  *   contributors may be used to endorse or promote products derived from this
    16  *   software without specific prior written permission.
    17  *
    18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
    19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    21  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
    22  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
    25  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    28  *
    29  * Contributor(s):
    30  *   Dave Townsend <dtownsend@oxymoronical.com>
    31  *   Josh Aas <josh@mozilla.com>
    32  *
    33  * ***** END LICENSE BLOCK ***** */
    35 #include "nptest.h"
    36 #include "nptest_utils.h"
    37 #include "nptest_platform.h"
    39 #include "mozilla/IntentionalCrash.h"
    41 #include <stdlib.h>
    42 #include <string.h>
    43 #include <stdio.h>
    44 #include <iostream>
    45 #include <string>
    46 #include <sstream>
    47 #include <list>
    48 #include <ctime>
    50 #ifdef XP_WIN
    51 #include <process.h>
    52 #include <float.h>
    53 #include <windows.h>
    54 #define getpid _getpid
    55 #define strcasecmp _stricmp
    56 #else
    57 #include <unistd.h>
    58 #include <pthread.h>
    59 #endif
    61 #include "mozilla/NullPtr.h"
    63 using namespace std;
    65 #define PLUGIN_VERSION     "1.0.0.0"
    66 #define ARRAY_LENGTH(a) (sizeof(a)/sizeof(a[0]))
    67 #define STATIC_ASSERT(condition)                                \
    68     extern void np_static_assert(int arg[(condition) ? 1 : -1])
    70 extern const char *sPluginName;
    71 extern const char *sPluginDescription;
    72 static char sPluginVersion[] = PLUGIN_VERSION;
    74 //
    75 // Intentional crash
    76 //
    78 int gCrashCount = 0;
    80 static void Crash()
    81 {
    82   int *pi = nullptr;
    83   *pi = 55; // Crash dereferencing null pointer
    84   ++gCrashCount;
    85 }
    87 static void
    88 IntentionalCrash()
    89 {
    90   mozilla::NoteIntentionalCrash("plugin");
    91   Crash();
    92 }
    94 //
    95 // static data
    96 //
    98 static NPNetscapeFuncs* sBrowserFuncs = nullptr;
    99 static NPClass sNPClass;
   101 void
   102 asyncCallback(void* cookie);
   104 //
   105 // identifiers
   106 //
   108 typedef bool (* ScriptableFunction)
   109   (NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   111 static bool npnEvaluateTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   112 static bool npnInvokeTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   113 static bool npnInvokeDefaultTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   114 static bool setUndefinedValueTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   115 static bool identifierToStringTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   116 static bool timerTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   117 static bool queryPrivateModeState(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   118 static bool lastReportedPrivateModeState(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   119 static bool hasWidget(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   120 static bool getEdge(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   121 static bool getClipRegionRectCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   122 static bool getClipRegionRectEdge(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   123 static bool startWatchingInstanceCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   124 static bool getInstanceCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   125 static bool stopWatchingInstanceCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   126 static bool getLastMouseX(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   127 static bool getLastMouseY(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   128 static bool getPaintCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   129 static bool getWidthAtLastPaint(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   130 static bool setInvalidateDuringPaint(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   131 static bool setSlowPaint(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   132 static bool getError(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   133 static bool doInternalConsistencyCheck(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   134 static bool setColor(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   135 static bool throwExceptionNextInvoke(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   136 static bool convertPointX(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   137 static bool convertPointY(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   138 static bool streamTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   139 static bool setPluginWantsAllStreams(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   140 static bool crashPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   141 static bool crashOnDestroy(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   142 static bool getObjectValue(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   143 static bool getJavaCodebase(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   144 static bool checkObjectValue(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   145 static bool enableFPExceptions(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   146 static bool setCookie(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   147 static bool getCookie(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   148 static bool getAuthInfo(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   149 static bool asyncCallbackTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   150 static bool checkGCRace(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   151 static bool hangPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   152 static bool stallPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   153 static bool getClipboardText(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   154 static bool callOnDestroy(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   155 static bool reinitWidget(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   156 static bool crashPluginInNestedLoop(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   157 static bool destroySharedGfxStuff(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   158 static bool propertyAndMethod(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   159 static bool getTopLevelWindowActivationState(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   160 static bool getTopLevelWindowActivationEventCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   161 static bool getFocusState(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   162 static bool getFocusEventCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   163 static bool getEventModel(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   164 static bool getReflector(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   165 static bool isVisible(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   166 static bool getWindowPosition(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   167 static bool constructObject(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   168 static bool setSitesWithData(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   169 static bool setSitesWithDataCapabilities(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   170 static bool getLastKeyText(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   171 static bool getNPNVdocumentOrigin(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   172 static bool getMouseUpEventCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   173 static bool queryContentsScaleFactor(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   175 static const NPUTF8* sPluginMethodIdentifierNames[] = {
   176   "npnEvaluateTest",
   177   "npnInvokeTest",
   178   "npnInvokeDefaultTest",
   179   "setUndefinedValueTest",
   180   "identifierToStringTest",
   181   "timerTest",
   182   "queryPrivateModeState",
   183   "lastReportedPrivateModeState",
   184   "hasWidget",
   185   "getEdge",
   186   "getClipRegionRectCount",
   187   "getClipRegionRectEdge",
   188   "startWatchingInstanceCount",
   189   "getInstanceCount",
   190   "stopWatchingInstanceCount",
   191   "getLastMouseX",
   192   "getLastMouseY",
   193   "getPaintCount",
   194   "getWidthAtLastPaint",
   195   "setInvalidateDuringPaint",
   196   "setSlowPaint",
   197   "getError",
   198   "doInternalConsistencyCheck",
   199   "setColor",
   200   "throwExceptionNextInvoke",
   201   "convertPointX",
   202   "convertPointY",
   203   "streamTest",
   204   "setPluginWantsAllStreams",
   205   "crash",
   206   "crashOnDestroy",
   207   "getObjectValue",
   208   "getJavaCodebase",
   209   "checkObjectValue",
   210   "enableFPExceptions",
   211   "setCookie",
   212   "getCookie",
   213   "getAuthInfo",
   214   "asyncCallbackTest",
   215   "checkGCRace",
   216   "hang",
   217   "stall",
   218   "getClipboardText",
   219   "callOnDestroy",
   220   "reinitWidget",
   221   "crashInNestedLoop",
   222   "destroySharedGfxStuff",
   223   "propertyAndMethod",
   224   "getTopLevelWindowActivationState",
   225   "getTopLevelWindowActivationEventCount",
   226   "getFocusState",
   227   "getFocusEventCount",
   228   "getEventModel",
   229   "getReflector",
   230   "isVisible",
   231   "getWindowPosition",
   232   "constructObject",
   233   "setSitesWithData",
   234   "setSitesWithDataCapabilities",
   235   "getLastKeyText",
   236   "getNPNVdocumentOrigin",
   237   "getMouseUpEventCount",
   238   "queryContentsScaleFactor"
   239 };
   240 static NPIdentifier sPluginMethodIdentifiers[ARRAY_LENGTH(sPluginMethodIdentifierNames)];
   241 static const ScriptableFunction sPluginMethodFunctions[] = {
   242   npnEvaluateTest,
   243   npnInvokeTest,
   244   npnInvokeDefaultTest,
   245   setUndefinedValueTest,
   246   identifierToStringTest,
   247   timerTest,
   248   queryPrivateModeState,
   249   lastReportedPrivateModeState,
   250   hasWidget,
   251   getEdge,
   252   getClipRegionRectCount,
   253   getClipRegionRectEdge,
   254   startWatchingInstanceCount,
   255   getInstanceCount,
   256   stopWatchingInstanceCount,
   257   getLastMouseX,
   258   getLastMouseY,
   259   getPaintCount,
   260   getWidthAtLastPaint,
   261   setInvalidateDuringPaint,
   262   setSlowPaint,
   263   getError,
   264   doInternalConsistencyCheck,
   265   setColor,
   266   throwExceptionNextInvoke,
   267   convertPointX,
   268   convertPointY,
   269   streamTest,
   270   setPluginWantsAllStreams,
   271   crashPlugin,
   272   crashOnDestroy,
   273   getObjectValue,
   274   getJavaCodebase,
   275   checkObjectValue,
   276   enableFPExceptions,
   277   setCookie,
   278   getCookie,
   279   getAuthInfo,
   280   asyncCallbackTest,
   281   checkGCRace,
   282   hangPlugin,
   283   stallPlugin,
   284   getClipboardText,
   285   callOnDestroy,
   286   reinitWidget,
   287   crashPluginInNestedLoop,
   288   destroySharedGfxStuff,
   289   propertyAndMethod,
   290   getTopLevelWindowActivationState,
   291   getTopLevelWindowActivationEventCount,
   292   getFocusState,
   293   getFocusEventCount,
   294   getEventModel,
   295   getReflector,
   296   isVisible,
   297   getWindowPosition,
   298   constructObject,
   299   setSitesWithData,
   300   setSitesWithDataCapabilities,
   301   getLastKeyText,
   302   getNPNVdocumentOrigin,
   303   getMouseUpEventCount,
   304   queryContentsScaleFactor
   305 };
   307 STATIC_ASSERT(ARRAY_LENGTH(sPluginMethodIdentifierNames) ==
   308               ARRAY_LENGTH(sPluginMethodFunctions));
   310 static const NPUTF8* sPluginPropertyIdentifierNames[] = {
   311   "propertyAndMethod"
   312 };
   313 static NPIdentifier sPluginPropertyIdentifiers[ARRAY_LENGTH(sPluginPropertyIdentifierNames)];
   314 static NPVariant sPluginPropertyValues[ARRAY_LENGTH(sPluginPropertyIdentifierNames)];
   316 struct URLNotifyData
   317 {
   318   const char* cookie;
   319   NPObject* writeCallback;
   320   NPObject* notifyCallback;
   321   NPObject* redirectCallback;
   322   bool allowRedirects;
   323   uint32_t size;
   324   char* data;
   325 };
   327 static URLNotifyData kNotifyData = {
   328   "static-cookie",
   329   nullptr,
   330   nullptr,
   331   nullptr,
   332   false,
   333   0,
   334   nullptr
   335 };
   337 static const char* SUCCESS_STRING = "pass";
   339 static bool sIdentifiersInitialized = false;
   341 struct timerEvent {
   342   int32_t timerIdReceive;
   343   int32_t timerIdSchedule;
   344   uint32_t timerInterval;
   345   bool timerRepeat;
   346   int32_t timerIdUnschedule;
   347 };
   348 static timerEvent timerEvents[] = {
   349   {-1, 0, 200, false, -1},
   350   {0, 0, 400, false, -1},
   351   {0, 0, 200, true, -1},
   352   {0, 1, 400, true, -1},
   353   {0, -1, 0, false, 0},
   354   {1, -1, 0, false, -1},
   355   {1, -1, 0, false, 1},
   356 };
   357 static uint32_t currentTimerEventCount = 0;
   358 static uint32_t totalTimerEvents = sizeof(timerEvents) / sizeof(timerEvent);
   360 /**
   361  * Incremented for every startWatchingInstanceCount.
   362  */
   363 static int32_t sCurrentInstanceCountWatchGeneration = 0;
   364 /**
   365  * Tracks the number of instances created or destroyed since the last
   366  * startWatchingInstanceCount.
   367  */
   368 static int32_t sInstanceCount = 0;
   369 /**
   370  * True when we've had a startWatchingInstanceCount with no corresponding
   371  * stopWatchingInstanceCount.
   372  */
   373 static bool sWatchingInstanceCount = false;
   375 /**
   376  * A list representing sites for which the plugin has stored data. See
   377  * NPP_ClearSiteData and NPP_GetSitesWithData.
   378  */
   379 struct siteData {
   380   string site;
   381   uint64_t flags;
   382   uint64_t age;
   383 };
   384 static list<siteData>* sSitesWithData;
   385 static bool sClearByAgeSupported;
   387 static void initializeIdentifiers()
   388 {
   389   if (!sIdentifiersInitialized) {
   390     NPN_GetStringIdentifiers(sPluginMethodIdentifierNames,
   391         ARRAY_LENGTH(sPluginMethodIdentifierNames), sPluginMethodIdentifiers);
   392     NPN_GetStringIdentifiers(sPluginPropertyIdentifierNames,
   393         ARRAY_LENGTH(sPluginPropertyIdentifierNames), sPluginPropertyIdentifiers);
   395     sIdentifiersInitialized = true;
   397     // Check whether nullptr is handled in NPN_GetStringIdentifiers
   398     NPIdentifier IDList[2];
   399     static char const *const kIDNames[2] = { nullptr, "setCookie" };
   400     NPN_GetStringIdentifiers(const_cast<const NPUTF8**>(kIDNames), 2, IDList);
   401   }
   402 }
   404 static void clearIdentifiers()
   405 {
   406   memset(sPluginMethodIdentifiers, 0,
   407       ARRAY_LENGTH(sPluginMethodIdentifiers) * sizeof(NPIdentifier));
   408   memset(sPluginPropertyIdentifiers, 0,
   409       ARRAY_LENGTH(sPluginPropertyIdentifiers) * sizeof(NPIdentifier));
   411   sIdentifiersInitialized = false;
   412 }
   414 static void addRange(InstanceData* instanceData, const char* range)
   415 {
   416   char rangestr[16];
   417   strncpy(rangestr, range, sizeof(rangestr));
   418   const char* str1 = strtok(rangestr, ",");
   419   const char* str2 = str1 ? strtok(nullptr, ",") : nullptr;
   420   if (str1 && str2) {
   421     TestRange* byterange = new TestRange;
   422     byterange->offset = atoi(str1);
   423     byterange->length = atoi(str2);
   424     byterange->waiting = true;
   425     byterange->next = instanceData->testrange;
   426     instanceData->testrange = byterange;
   427   }
   428 }
   430 static void sendBufferToFrame(NPP instance)
   431 {
   432   InstanceData* instanceData = (InstanceData*)(instance->pdata);
   433   string outbuf;
   434   if (!instanceData->npnNewStream) outbuf = "data:text/html,";
   435   const char* buf = reinterpret_cast<char *>(instanceData->streamBuf);
   436   int32_t bufsize = instanceData->streamBufSize;
   437   if (instanceData->streamMode == NP_ASFILE ||
   438       instanceData->streamMode == NP_ASFILEONLY) {
   439     buf = reinterpret_cast<char *>(instanceData->fileBuf);
   440     bufsize = instanceData->fileBufSize;
   441   }
   442   if (instanceData->err.str().length() > 0) {
   443     outbuf.append(instanceData->err.str());
   444   }
   445   else if (bufsize > 0) {
   446     outbuf.append(buf);
   447   }
   448   else {
   449     outbuf.append("Error: no data in buffer");
   450   }
   452   if (instanceData->npnNewStream &&
   453       instanceData->err.str().length() == 0) {
   454     char typeHTML[] = "text/html";
   455     NPStream* stream;
   456     printf("calling NPN_NewStream...");
   457     NPError err = NPN_NewStream(instance, typeHTML,
   458         instanceData->frame.c_str(), &stream);
   459     printf("return value %d\n", err);
   460     if (err != NPERR_NO_ERROR) {
   461       instanceData->err << "NPN_NewStream returned " << err;
   462       return;
   463     }
   465     int32_t bytesToWrite = outbuf.length();
   466     int32_t bytesWritten = 0;
   467     while ((bytesToWrite - bytesWritten) > 0) {
   468       int32_t numBytes = (bytesToWrite - bytesWritten) <
   469           instanceData->streamChunkSize ?
   470           bytesToWrite - bytesWritten : instanceData->streamChunkSize;
   471       int32_t written = NPN_Write(instance, stream,
   472           numBytes, (void*)(outbuf.c_str() + bytesWritten));
   473       if (written <= 0) {
   474         instanceData->err << "NPN_Write returned " << written;
   475         break;
   476       }
   477       bytesWritten += numBytes;
   478       printf("%d bytes written, total %d\n", written, bytesWritten);
   479     }
   480     err = NPN_DestroyStream(instance, stream, NPRES_DONE);
   481     if (err != NPERR_NO_ERROR) {
   482       instanceData->err << "NPN_DestroyStream returned " << err;
   483     }
   484   }
   485   else {
   486     // Convert CRLF to LF, and escape most other non-alphanumeric chars.
   487     for (size_t i = 0; i < outbuf.length(); i++) {
   488       if (outbuf[i] == '\n') {
   489         outbuf.replace(i, 1, "%0a");
   490         i += 2;
   491       }
   492       else if (outbuf[i] == '\r') {
   493         outbuf.replace(i, 1, "");
   494         i -= 1;
   495       }
   496       else {
   497         int ascii = outbuf[i];
   498         if (!((ascii >= ',' && ascii <= ';') ||
   499               (ascii >= 'A' && ascii <= 'Z') ||
   500               (ascii >= 'a' && ascii <= 'z'))) {
   501           char hex[8];
   502           sprintf(hex, "%%%x", ascii);
   503           outbuf.replace(i, 1, hex);
   504           i += 2;
   505         }
   506       }
   507     }
   509     NPError err = NPN_GetURL(instance, outbuf.c_str(),
   510                              instanceData->frame.c_str());
   511     if (err != NPERR_NO_ERROR) {
   512       instanceData->err << "NPN_GetURL returned " << err;
   513     }
   514   }
   515 }
   517 static void XPSleep(unsigned int seconds)
   518 {
   519 #ifdef XP_WIN
   520   Sleep(1000 * seconds);
   521 #else
   522   sleep(seconds);
   523 #endif
   524 }
   526 TestFunction
   527 getFuncFromString(const char* funcname)
   528 {
   529   FunctionTable funcTable[] =
   530     {
   531       { FUNCTION_NPP_NEWSTREAM, "npp_newstream" },
   532       { FUNCTION_NPP_WRITEREADY, "npp_writeready" },
   533       { FUNCTION_NPP_WRITE, "npp_write" },
   534       { FUNCTION_NPP_DESTROYSTREAM, "npp_destroystream" },
   535       { FUNCTION_NPP_WRITE_RPC, "npp_write_rpc" },
   536       { FUNCTION_NONE, nullptr }
   537     };
   538   int32_t i = 0;
   539   while(funcTable[i].funcName) {
   540     if (!strcmp(funcname, funcTable[i].funcName)) return funcTable[i].funcId;
   541     i++;
   542   }
   543   return FUNCTION_NONE;
   544 }
   546 static void
   547 DuplicateNPVariant(NPVariant& aDest, const NPVariant& aSrc)
   548 {
   549   if (NPVARIANT_IS_STRING(aSrc)) {
   550     NPString src = NPVARIANT_TO_STRING(aSrc);
   551     char* buf = new char[src.UTF8Length];
   552     strncpy(buf, src.UTF8Characters, src.UTF8Length);
   553     STRINGN_TO_NPVARIANT(buf, src.UTF8Length, aDest);
   554   }
   555   else if (NPVARIANT_IS_OBJECT(aSrc)) {
   556     NPObject* obj =
   557       NPN_RetainObject(NPVARIANT_TO_OBJECT(aSrc));
   558     OBJECT_TO_NPVARIANT(obj, aDest);
   559   }
   560   else {
   561     aDest = aSrc;
   562   }
   563 }
   565 void
   566 drawAsyncBitmapColor(InstanceData* instanceData)
   567 {
   568   NPP npp = instanceData->npp;
   570   uint32_t *pixelData = (uint32_t*)instanceData->backBuffer->bitmap.data;
   572   uint32_t rgba = instanceData->scriptableObject->drawColor;
   574   unsigned char subpixels[4];
   575   subpixels[0] = rgba & 0xFF;
   576   subpixels[1] = (rgba & 0xFF00) >> 8;
   577   subpixels[2] = (rgba & 0xFF0000) >> 16;
   578   subpixels[3] = (rgba & 0xFF000000) >> 24;
   580   subpixels[0] = uint8_t(float(subpixels[3] * subpixels[0]) / 0xFF);
   581   subpixels[1] = uint8_t(float(subpixels[3] * subpixels[1]) / 0xFF);
   582   subpixels[2] = uint8_t(float(subpixels[3] * subpixels[2]) / 0xFF);
   583   uint32_t premultiplied;
   584   memcpy(&premultiplied, subpixels, sizeof(premultiplied));
   586   for (uint32_t* lastPixel = pixelData + instanceData->backBuffer->size.width * instanceData->backBuffer->size.height;
   587 	pixelData < lastPixel;
   588 	++pixelData) {
   589     *pixelData = premultiplied;
   590   }
   592   NPN_SetCurrentAsyncSurface(npp, instanceData->backBuffer, nullptr);
   593   NPAsyncSurface *oldFront = instanceData->frontBuffer;
   594   instanceData->frontBuffer = instanceData->backBuffer;
   595   instanceData->backBuffer = oldFront;
   596 }
   598 static bool bug813906(NPP npp, const char* const function, const char* const url, const char* const frame)
   599 {
   600   NPObject *windowObj = nullptr;
   601   NPError err = NPN_GetValue(npp, NPNVWindowNPObject, &windowObj);
   602   if (err != NPERR_NO_ERROR) {
   603     return false;
   604   }
   606   NPVariant result;
   607   bool res = NPN_Invoke(npp, windowObj, NPN_GetStringIdentifier(function), nullptr, 0, &result);
   608   NPN_ReleaseObject(windowObj);
   609   if (!res) {
   610     return false;
   611   }
   613   NPN_ReleaseVariantValue(&result);
   615   err = NPN_GetURL(npp, url, frame);
   616   if (err != NPERR_NO_ERROR) {
   617     err = NPN_GetURL(npp, "about:blank", frame);
   618     return false;
   619   }
   621   return true;
   622 }
   624 //
   625 // function signatures
   626 //
   628 NPObject* scriptableAllocate(NPP npp, NPClass* aClass);
   629 void scriptableDeallocate(NPObject* npobj);
   630 void scriptableInvalidate(NPObject* npobj);
   631 bool scriptableHasMethod(NPObject* npobj, NPIdentifier name);
   632 bool scriptableInvoke(NPObject* npobj, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result);
   633 bool scriptableInvokeDefault(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   634 bool scriptableHasProperty(NPObject* npobj, NPIdentifier name);
   635 bool scriptableGetProperty(NPObject* npobj, NPIdentifier name, NPVariant* result);
   636 bool scriptableSetProperty(NPObject* npobj, NPIdentifier name, const NPVariant* value);
   637 bool scriptableRemoveProperty(NPObject* npobj, NPIdentifier name);
   638 bool scriptableEnumerate(NPObject* npobj, NPIdentifier** identifier, uint32_t* count);
   639 bool scriptableConstruct(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
   641 //
   642 // npapi plugin functions
   643 //
   645 #ifdef XP_UNIX
   646 NP_EXPORT(char*)
   647 NP_GetPluginVersion()
   648 {
   649   return sPluginVersion;
   650 }
   651 #endif
   653 extern const char *sMimeDescription;
   655 #if defined(XP_UNIX)
   656 NP_EXPORT(const char*) NP_GetMIMEDescription()
   657 #elif defined(XP_WIN)
   658 const char* NP_GetMIMEDescription()
   659 #endif
   660 {
   661   return sMimeDescription;
   662 }
   664 #ifdef XP_UNIX
   665 NP_EXPORT(NPError)
   666 NP_GetValue(void* future, NPPVariable aVariable, void* aValue) {
   667   switch (aVariable) {
   668     case NPPVpluginNameString:
   669       *((const char**)aValue) = sPluginName;
   670       break;
   671     case NPPVpluginDescriptionString:
   672       *((const char**)aValue) = sPluginDescription;
   673       break;
   674     default:
   675       return NPERR_INVALID_PARAM;
   676       break;
   677   }
   678   return NPERR_NO_ERROR;
   679 }
   680 #endif
   682 static bool fillPluginFunctionTable(NPPluginFuncs* pFuncs)
   683 {
   684   // Check the size of the provided structure based on the offset of the
   685   // last member we need.
   686   if (pFuncs->size < (offsetof(NPPluginFuncs, getsiteswithdata) + sizeof(void*)))
   687     return false;
   689   pFuncs->newp = NPP_New;
   690   pFuncs->destroy = NPP_Destroy;
   691   pFuncs->setwindow = NPP_SetWindow;
   692   pFuncs->newstream = NPP_NewStream;
   693   pFuncs->destroystream = NPP_DestroyStream;
   694   pFuncs->asfile = NPP_StreamAsFile;
   695   pFuncs->writeready = NPP_WriteReady;
   696   pFuncs->write = NPP_Write;
   697   pFuncs->print = NPP_Print;
   698   pFuncs->event = NPP_HandleEvent;
   699   pFuncs->urlnotify = NPP_URLNotify;
   700   pFuncs->getvalue = NPP_GetValue;
   701   pFuncs->setvalue = NPP_SetValue;
   702   pFuncs->urlredirectnotify = NPP_URLRedirectNotify;
   703   pFuncs->clearsitedata = NPP_ClearSiteData;
   704   pFuncs->getsiteswithdata = NPP_GetSitesWithData;
   706   return true;
   707 }
   709 #if defined(XP_MACOSX)
   710 NP_EXPORT(NPError) NP_Initialize(NPNetscapeFuncs* bFuncs)
   711 #elif defined(XP_WIN)
   712 NPError OSCALL NP_Initialize(NPNetscapeFuncs* bFuncs)
   713 #elif defined(XP_UNIX)
   714 NP_EXPORT(NPError) NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs)
   715 #endif
   716 {
   717   sBrowserFuncs = bFuncs;
   719   initializeIdentifiers();
   721   for (unsigned int i = 0; i < ARRAY_LENGTH(sPluginPropertyValues); i++) {
   722     VOID_TO_NPVARIANT(sPluginPropertyValues[i]);
   723   }
   725   memset(&sNPClass, 0, sizeof(NPClass));
   726   sNPClass.structVersion =  NP_CLASS_STRUCT_VERSION;
   727   sNPClass.allocate =       (NPAllocateFunctionPtr)scriptableAllocate;
   728   sNPClass.deallocate =     (NPDeallocateFunctionPtr)scriptableDeallocate;
   729   sNPClass.invalidate =     (NPInvalidateFunctionPtr)scriptableInvalidate;
   730   sNPClass.hasMethod =      (NPHasMethodFunctionPtr)scriptableHasMethod;
   731   sNPClass.invoke =         (NPInvokeFunctionPtr)scriptableInvoke;
   732   sNPClass.invokeDefault =  (NPInvokeDefaultFunctionPtr)scriptableInvokeDefault;
   733   sNPClass.hasProperty =    (NPHasPropertyFunctionPtr)scriptableHasProperty;
   734   sNPClass.getProperty =    (NPGetPropertyFunctionPtr)scriptableGetProperty;
   735   sNPClass.setProperty =    (NPSetPropertyFunctionPtr)scriptableSetProperty;
   736   sNPClass.removeProperty = (NPRemovePropertyFunctionPtr)scriptableRemoveProperty;
   737   sNPClass.enumerate =      (NPEnumerationFunctionPtr)scriptableEnumerate;
   738   sNPClass.construct =      (NPConstructFunctionPtr)scriptableConstruct;
   740 #if defined(XP_UNIX) && !defined(XP_MACOSX)
   741   if (!fillPluginFunctionTable(pFuncs)) {
   742     return NPERR_INVALID_FUNCTABLE_ERROR;
   743   }
   744 #endif
   746   return NPERR_NO_ERROR;
   747 }
   749 #if defined(XP_MACOSX)
   750 NP_EXPORT(NPError) NP_GetEntryPoints(NPPluginFuncs* pFuncs)
   751 #elif defined(XP_WIN)
   752 NPError OSCALL NP_GetEntryPoints(NPPluginFuncs* pFuncs)
   753 #endif
   754 #if defined(XP_MACOSX) || defined(XP_WIN)
   755 {
   756   if (!fillPluginFunctionTable(pFuncs)) {
   757     return NPERR_INVALID_FUNCTABLE_ERROR;
   758   }
   760   return NPERR_NO_ERROR;
   761 }
   762 #endif
   764 #if defined(XP_UNIX)
   765 NP_EXPORT(NPError) NP_Shutdown()
   766 #elif defined(XP_WIN)
   767 NPError OSCALL NP_Shutdown()
   768 #endif
   769 {
   770   clearIdentifiers();
   772   for (unsigned int i = 0; i < ARRAY_LENGTH(sPluginPropertyValues); i++) {
   773     NPN_ReleaseVariantValue(&sPluginPropertyValues[i]);
   774   }
   776   return NPERR_NO_ERROR;
   777 }
   779 NPError
   780 NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved)
   781 {
   782   // Make sure our pdata field is nullptr at this point. If it isn't, that
   783   // probably means the browser gave us uninitialized memory.
   784   if (instance->pdata) {
   785     printf("NPP_New called with non-NULL NPP->pdata pointer!\n");
   786     return NPERR_GENERIC_ERROR;
   787   }
   789   // Make sure we can render this plugin
   790   NPBool browserSupportsWindowless = false;
   791   NPN_GetValue(instance, NPNVSupportsWindowless, &browserSupportsWindowless);
   792   if (!browserSupportsWindowless && !pluginSupportsWindowMode()) {
   793     printf("Windowless mode not supported by the browser, windowed mode not supported by the plugin!\n");
   794     return NPERR_GENERIC_ERROR;
   795   }
   797   // set up our our instance data
   798   InstanceData* instanceData = new InstanceData;
   799   if (!instanceData)
   800     return NPERR_OUT_OF_MEMORY_ERROR;
   801   instanceData->npp = instance;
   802   instanceData->streamMode = NP_ASFILEONLY;
   803   instanceData->testFunction = FUNCTION_NONE;
   804   instanceData->functionToFail = FUNCTION_NONE;
   805   instanceData->failureCode = 0;
   806   instanceData->callOnDestroy = nullptr;
   807   instanceData->streamChunkSize = 1024;
   808   instanceData->streamBuf = nullptr;
   809   instanceData->streamBufSize = 0;
   810   instanceData->fileBuf = nullptr;
   811   instanceData->fileBufSize = 0;
   812   instanceData->throwOnNextInvoke = false;
   813   instanceData->runScriptOnPaint = false;
   814   instanceData->dontTouchElement = false;
   815   instanceData->testrange = nullptr;
   816   instanceData->hasWidget = false;
   817   instanceData->npnNewStream = false;
   818   instanceData->invalidateDuringPaint = false;
   819   instanceData->slowPaint = false;
   820   instanceData->writeCount = 0;
   821   instanceData->writeReadyCount = 0;
   822   memset(&instanceData->window, 0, sizeof(instanceData->window));
   823   instanceData->crashOnDestroy = false;
   824   instanceData->cleanupWidget = true; // only used by nptest_gtk
   825   instanceData->topLevelWindowActivationState = ACTIVATION_STATE_UNKNOWN;
   826   instanceData->topLevelWindowActivationEventCount = 0;
   827   instanceData->focusState = ACTIVATION_STATE_UNKNOWN;
   828   instanceData->focusEventCount = 0;
   829   instanceData->eventModel = 0;
   830   instanceData->closeStream = false;
   831   instanceData->wantsAllStreams = false;
   832   instanceData->asyncDrawing = AD_NONE;
   833   instanceData->frontBuffer = nullptr;
   834   instanceData->backBuffer = nullptr;
   835   instanceData->mouseUpEventCount = 0;
   836   instanceData->bugMode = -1;
   837   instance->pdata = instanceData;
   839   TestNPObject* scriptableObject = (TestNPObject*)NPN_CreateObject(instance, &sNPClass);
   840   if (!scriptableObject) {
   841     printf("NPN_CreateObject failed to create an object, can't create a plugin instance\n");
   842     free(instanceData);
   843     return NPERR_GENERIC_ERROR;
   844   }
   845   scriptableObject->npp = instance;
   846   scriptableObject->drawMode = DM_DEFAULT;
   847   scriptableObject->drawColor = 0;
   848   instanceData->scriptableObject = scriptableObject;
   850   instanceData->instanceCountWatchGeneration = sCurrentInstanceCountWatchGeneration;
   852   if (NP_FULL == mode) {
   853     instanceData->streamMode = NP_SEEK;
   854     instanceData->frame = "testframe";
   855     addRange(instanceData, "100,100");
   856   }
   858   bool requestWindow = false;
   859   // handle extra params
   860   for (int i = 0; i < argc; i++) {
   861     if (strcmp(argn[i], "drawmode") == 0) {
   862       if (strcmp(argv[i], "solid") == 0)
   863         scriptableObject->drawMode = DM_SOLID_COLOR;
   864     }
   865     else if (strcmp(argn[i], "color") == 0) {
   866       scriptableObject->drawColor = parseHexColor(argv[i], strlen(argv[i]));
   867     }
   868     else if (strcmp(argn[i], "wmode") == 0) {
   869       if (strcmp(argv[i], "window") == 0) {
   870         requestWindow = true;
   871       }
   872     }
   873     else if (strcmp(argn[i], "asyncmodel") == 0) {
   874       if (strcmp(argv[i], "bitmap") == 0) {
   875         if (pluginSupportsAsyncBitmapDrawing()) {
   876           instanceData->asyncDrawing = AD_BITMAP;
   877         }
   878       }
   879       if (strcmp(argv[i], "dxgi") == 0) {
   880         if (pluginSupportsAsyncDXGIDrawing()) {
   881           instanceData->asyncDrawing = AD_DXGI;
   882         }
   883       }
   884     }
   885     if (strcmp(argn[i], "streammode") == 0) {
   886       if (strcmp(argv[i], "normal") == 0) {
   887         instanceData->streamMode = NP_NORMAL;
   888       }
   889       else if ((strcmp(argv[i], "asfile") == 0) &&
   890                 strlen(argv[i]) == strlen("asfile")) {
   891         instanceData->streamMode = NP_ASFILE;
   892       }
   893       else if (strcmp(argv[i], "asfileonly") == 0) {
   894         instanceData->streamMode = NP_ASFILEONLY;
   895       }
   896       else if (strcmp(argv[i], "seek") == 0) {
   897         instanceData->streamMode = NP_SEEK;
   898       }
   899     }
   900     if (strcmp(argn[i], "streamchunksize") == 0) {
   901       instanceData->streamChunkSize = atoi(argv[i]);
   902     }
   903     if (strcmp(argn[i], "failurecode") == 0) {
   904       instanceData->failureCode = atoi(argv[i]);
   905     }
   906     if (strcmp(argn[i], "functiontofail") == 0) {
   907       instanceData->functionToFail = getFuncFromString(argv[i]);
   908     }
   909     if (strcmp(argn[i], "geturl") == 0) {
   910       instanceData->testUrl = argv[i];
   911       instanceData->testFunction = FUNCTION_NPP_GETURL;
   912     }
   913     if (strcmp(argn[i], "posturl") == 0) {
   914       instanceData->testUrl = argv[i];
   915       instanceData->testFunction = FUNCTION_NPP_POSTURL;
   916     }
   917     if (strcmp(argn[i], "geturlnotify") == 0) {
   918       instanceData->testUrl = argv[i];
   919       instanceData->testFunction = FUNCTION_NPP_GETURLNOTIFY;
   920     }
   921     if (strcmp(argn[i], "postmode") == 0) {
   922       if (strcmp(argv[i], "frame") == 0) {
   923         instanceData->postMode = POSTMODE_FRAME;
   924       }
   925       else if (strcmp(argv[i], "stream") == 0) {
   926         instanceData->postMode = POSTMODE_STREAM;
   927       }
   928     }
   929     if (strcmp(argn[i], "frame") == 0) {
   930       instanceData->frame = argv[i];
   931     }
   932     if (strcmp(argn[i], "range") == 0) {
   933       string range = argv[i];
   934       size_t semicolon = range.find(';');
   935       while (semicolon != string::npos) {
   936         addRange(instanceData, range.substr(0, semicolon).c_str());
   937         if (semicolon == range.length()) {
   938           range = "";
   939           break;
   940         }
   941         range = range.substr(semicolon + 1);
   942         semicolon = range.find(';');
   943       }
   944       if (range.length()) addRange(instanceData, range.c_str());
   945     }
   946     if (strcmp(argn[i], "newstream") == 0 &&
   947         strcmp(argv[i], "true") == 0) {
   948       instanceData->npnNewStream = true;
   949     }
   950     if (strcmp(argn[i], "newcrash") == 0) {
   951       IntentionalCrash();
   952     }
   953     if (strcmp(argn[i], "paintscript") == 0) {
   954       instanceData->runScriptOnPaint = true;
   955     }
   957     if (strcmp(argn[i], "donttouchelement") == 0) {
   958       instanceData->dontTouchElement = true;
   959     }
   960     // "cleanupwidget" is only used with nptest_gtk, defaulting to true.  It
   961     // indicates whether the plugin should destroy its window in response to
   962     // NPP_Destroy (or let the platform destroy the widget when the parent
   963     // window gets destroyed).
   964     if (strcmp(argn[i], "cleanupwidget") == 0 &&
   965         strcmp(argv[i], "false") == 0) {
   966       instanceData->cleanupWidget = false;
   967     }
   968     if (!strcmp(argn[i], "closestream")) {
   969       instanceData->closeStream = true;
   970     }
   971     if (strcmp(argn[i], "bugmode") == 0) {
   972       instanceData->bugMode = atoi(argv[i]);
   973     }
   974     // Try to emulate java's codebase handling: Use the last seen codebase
   975     // value, regardless of whether it is in attributes or params.
   976     if (strcasecmp(argn[i], "codebase") == 0) {
   977       instanceData->javaCodebase = argv[i];
   978     }
   979   }
   981   if (!browserSupportsWindowless || !pluginSupportsWindowlessMode()) {
   982     requestWindow = true;
   983   } else if (!pluginSupportsWindowMode()) {
   984     requestWindow = false;
   985   }
   986   if (requestWindow) {
   987     instanceData->hasWidget = true;
   988   } else {
   989     // NPPVpluginWindowBool should default to true, so we may as well
   990     // test that by not setting it in the window case
   991     NPN_SetValue(instance, NPPVpluginWindowBool, (void*)false);
   992   }
   994   if (scriptableObject->drawMode == DM_SOLID_COLOR &&
   995       (scriptableObject->drawColor & 0xFF000000) != 0xFF000000) {
   996     NPN_SetValue(instance, NPPVpluginTransparentBool, (void*)true);
   997   }
   999   if (instanceData->asyncDrawing == AD_BITMAP) {
  1000     NPBool supportsAsyncBitmap = false;
  1001     if ((NPN_GetValue(instance, NPNVsupportsAsyncBitmapSurfaceBool, &supportsAsyncBitmap) == NPERR_NO_ERROR) &&
  1002         supportsAsyncBitmap) {
  1003       NPN_SetValue(instance, NPPVpluginDrawingModel, (void*)NPDrawingModelAsyncBitmapSurface);
  1004     } else {
  1005       instanceData->asyncDrawing = AD_NONE;
  1008 #ifdef XP_WIN
  1009   else if (instanceData->asyncDrawing == AD_DXGI) {
  1010     NPBool supportsAsyncDXGI = false;
  1011     if ((NPN_GetValue(instance, NPNVsupportsAsyncWindowsDXGISurfaceBool, &supportsAsyncDXGI) == NPERR_NO_ERROR) &&
  1012         supportsAsyncDXGI) {
  1013       NPN_SetValue(instance, NPPVpluginDrawingModel, (void*)NPDrawingModelAsyncWindowsDXGISurface);
  1014     } else {
  1015       instanceData->asyncDrawing = AD_NONE;
  1018 #endif
  1020   instanceData->lastReportedPrivateModeState = false;
  1021   instanceData->lastMouseX = instanceData->lastMouseY = -1;
  1022   instanceData->widthAtLastPaint = -1;
  1023   instanceData->paintCount = 0;
  1025   // do platform-specific initialization
  1026   NPError err = pluginInstanceInit(instanceData);
  1027   if (err != NPERR_NO_ERROR) {
  1028     NPN_ReleaseObject(scriptableObject);
  1029     free(instanceData);
  1030     return err;
  1033   NPVariant variantTrue;
  1034   BOOLEAN_TO_NPVARIANT(true, variantTrue);
  1035   NPObject* o = nullptr;
  1037   // Set a property on NPNVPluginElementNPObject, unless the consumer explicitly
  1038   // opted out of this behavior.
  1039   if (!instanceData->dontTouchElement) {
  1040     err = NPN_GetValue(instance, NPNVPluginElementNPObject, &o);
  1041     if (err == NPERR_NO_ERROR) {
  1042       NPN_SetProperty(instance, o,
  1043                       NPN_GetStringIdentifier("pluginFoundElement"), &variantTrue);
  1044       NPN_ReleaseObject(o);
  1045       o = nullptr;
  1049   // Set a property on NPNVWindowNPObject
  1050   err = NPN_GetValue(instance, NPNVWindowNPObject, &o);
  1051   if (err == NPERR_NO_ERROR) {
  1052     NPN_SetProperty(instance, o,
  1053                     NPN_GetStringIdentifier("pluginFoundWindow"), &variantTrue);
  1054     NPN_ReleaseObject(o);
  1055     o = nullptr;
  1058   ++sInstanceCount;
  1060   if (instanceData->testFunction == FUNCTION_NPP_GETURL) {
  1061     NPError err = NPN_GetURL(instance, instanceData->testUrl.c_str(), nullptr);
  1062     if (err != NPERR_NO_ERROR) {
  1063       instanceData->err << "NPN_GetURL returned " << err;
  1066   else if (instanceData->testFunction == FUNCTION_NPP_GETURLNOTIFY) {
  1067     NPError err = NPN_GetURLNotify(instance, instanceData->testUrl.c_str(),
  1068                                    nullptr, static_cast<void*>(&kNotifyData));
  1069     if (err != NPERR_NO_ERROR) {
  1070       instanceData->err << "NPN_GetURLNotify returned " << err;
  1074   if ((instanceData->bugMode == 813906) && instanceData->frame.length()) {
  1075     bug813906(instance, "f", "browser.xul", instanceData->frame.c_str());
  1078   return NPERR_NO_ERROR;
  1081 NPError
  1082 NPP_Destroy(NPP instance, NPSavedData** save)
  1084   printf("NPP_Destroy\n");
  1085   InstanceData* instanceData = (InstanceData*)(instance->pdata);
  1087   if (instanceData->crashOnDestroy)
  1088     IntentionalCrash();
  1090   if (instanceData->callOnDestroy) {
  1091     NPVariant result;
  1092     NPN_InvokeDefault(instance, instanceData->callOnDestroy, nullptr, 0, &result);
  1093     NPN_ReleaseVariantValue(&result);
  1094     NPN_ReleaseObject(instanceData->callOnDestroy);
  1097   if (instanceData->streamBuf) {
  1098     free(instanceData->streamBuf);
  1100   if (instanceData->fileBuf) {
  1101     free(instanceData->fileBuf);
  1104   TestRange* currentrange = instanceData->testrange;
  1105   TestRange* nextrange;
  1106   while (currentrange != nullptr) {
  1107     nextrange = reinterpret_cast<TestRange*>(currentrange->next);
  1108     delete currentrange;
  1109     currentrange = nextrange;
  1112   if (instanceData->frontBuffer) {
  1113     NPN_SetCurrentAsyncSurface(instance, nullptr, nullptr);
  1114     NPN_FinalizeAsyncSurface(instance, instanceData->frontBuffer);
  1115     NPN_MemFree(instanceData->frontBuffer);
  1117   if (instanceData->backBuffer) {
  1118     NPN_FinalizeAsyncSurface(instance, instanceData->backBuffer);
  1119     NPN_MemFree(instanceData->backBuffer);
  1122   pluginInstanceShutdown(instanceData);
  1123   NPN_ReleaseObject(instanceData->scriptableObject);
  1125   if (sCurrentInstanceCountWatchGeneration == instanceData->instanceCountWatchGeneration) {
  1126     --sInstanceCount;
  1128   delete instanceData;
  1130   return NPERR_NO_ERROR;
  1133 NPError
  1134 NPP_SetWindow(NPP instance, NPWindow* window)
  1136   InstanceData* instanceData = (InstanceData*)(instance->pdata);
  1138   if (instanceData->scriptableObject->drawMode == DM_DEFAULT &&
  1139       (instanceData->window.width != window->width ||
  1140        instanceData->window.height != window->height)) {
  1141     NPRect r;
  1142     r.left = r.top = 0;
  1143     r.right = window->width;
  1144     r.bottom = window->height;
  1145     NPN_InvalidateRect(instance, &r);
  1148   void* oldWindow = instanceData->window.window;
  1149   pluginDoSetWindow(instanceData, window);
  1150   if (instanceData->hasWidget && oldWindow != instanceData->window.window) {
  1151     pluginWidgetInit(instanceData, oldWindow);
  1154   if (instanceData->asyncDrawing == AD_BITMAP) {
  1155     if (instanceData->frontBuffer &&
  1156 	instanceData->frontBuffer->size.width >= 0 &&
  1157        (uint32_t)instanceData->frontBuffer->size.width == window->width &&
  1158        instanceData ->frontBuffer->size.height >= 0 &&
  1159        (uint32_t)instanceData->frontBuffer->size.height == window->height) {
  1160           return NPERR_NO_ERROR;
  1162     if (instanceData->frontBuffer) {
  1163       NPN_FinalizeAsyncSurface(instance, instanceData->frontBuffer);
  1164       NPN_MemFree(instanceData->frontBuffer);
  1166     if (instanceData->backBuffer) {
  1167       NPN_FinalizeAsyncSurface(instance, instanceData->backBuffer);
  1168       NPN_MemFree(instanceData->backBuffer);
  1170     instanceData->frontBuffer = (NPAsyncSurface*)NPN_MemAlloc(sizeof(NPAsyncSurface));
  1171     instanceData->backBuffer = (NPAsyncSurface*)NPN_MemAlloc(sizeof(NPAsyncSurface));
  1173     NPSize size;
  1174     size.width = window->width;
  1175     size.height = window->height;
  1177     memcpy(instanceData->backBuffer, instanceData->frontBuffer, sizeof(NPAsyncSurface));
  1179     NPN_InitAsyncSurface(instance, &size, NPImageFormatBGRA32, nullptr, instanceData->frontBuffer);
  1180     NPN_InitAsyncSurface(instance, &size, NPImageFormatBGRA32, nullptr, instanceData->backBuffer);
  1182     drawAsyncBitmapColor(instanceData);
  1184   return NPERR_NO_ERROR;
  1187 NPError
  1188 NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype)
  1190   printf("NPP_NewStream\n");
  1191   InstanceData* instanceData = (InstanceData*)(instance->pdata);
  1193   if (instanceData->functionToFail == FUNCTION_NPP_NEWSTREAM &&
  1194       instanceData->failureCode) {
  1195     instanceData->err << SUCCESS_STRING;
  1196     if (instanceData->frame.length() > 0) {
  1197       sendBufferToFrame(instance);
  1199     return instanceData->failureCode;
  1202   if (stream->notifyData &&
  1203       static_cast<URLNotifyData*>(stream->notifyData) != &kNotifyData) {
  1204     // stream from streamTest
  1205     *stype = NP_NORMAL;
  1207   else {
  1208     *stype = instanceData->streamMode;
  1210     if (instanceData->streamBufSize) {
  1211       free(instanceData->streamBuf);
  1212       instanceData->streamBufSize = 0;
  1213       if (instanceData->testFunction == FUNCTION_NPP_POSTURL &&
  1214           instanceData->postMode == POSTMODE_STREAM) {
  1215         instanceData->testFunction = FUNCTION_NPP_GETURL;
  1217       else {
  1218         // We already got a stream and didn't ask for another one.
  1219         instanceData->err << "Received unexpected multiple NPP_NewStream";
  1223   return NPERR_NO_ERROR;
  1226 NPError
  1227 NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason)
  1229   printf("NPP_DestroyStream\n");
  1230   InstanceData* instanceData = (InstanceData*)(instance->pdata);
  1232   if (instanceData->functionToFail == FUNCTION_NPP_NEWSTREAM) {
  1233     instanceData->err << "NPP_DestroyStream called";
  1236   if (instanceData->functionToFail == FUNCTION_NPP_WRITE) {
  1237     if (instanceData->writeCount == 1)
  1238       instanceData->err << SUCCESS_STRING;
  1239     else
  1240       instanceData->err << "NPP_Write called after returning -1";
  1243   if (instanceData->functionToFail == FUNCTION_NPP_DESTROYSTREAM &&
  1244       instanceData->failureCode) {
  1245     instanceData->err << SUCCESS_STRING;
  1246     if (instanceData->frame.length() > 0) {
  1247       sendBufferToFrame(instance);
  1249     return instanceData->failureCode;
  1252   URLNotifyData* nd = static_cast<URLNotifyData*>(stream->notifyData);
  1253   if (nd && nd != &kNotifyData) {
  1254     return NPERR_NO_ERROR;
  1257   if (instanceData->streamMode == NP_ASFILE &&
  1258       instanceData->functionToFail == FUNCTION_NONE) {
  1259     if (!instanceData->streamBuf) {
  1260       instanceData->err <<
  1261         "Error: no data written with NPP_Write";
  1262       return NPERR_GENERIC_ERROR;
  1265     if (!instanceData->fileBuf) {
  1266       instanceData->err <<
  1267         "Error: no data written with NPP_StreamAsFile";
  1268       return NPERR_GENERIC_ERROR;
  1271     if (strcmp(reinterpret_cast<char *>(instanceData->fileBuf),
  1272                reinterpret_cast<char *>(instanceData->streamBuf))) {
  1273       instanceData->err <<
  1274         "Error: data passed to NPP_Write and NPP_StreamAsFile differed";
  1277   if (instanceData->frame.length() > 0 &&
  1278       instanceData->testFunction != FUNCTION_NPP_GETURLNOTIFY &&
  1279       instanceData->testFunction != FUNCTION_NPP_POSTURL) {
  1280     sendBufferToFrame(instance);
  1282   if (instanceData->testFunction == FUNCTION_NPP_POSTURL) {
  1283     NPError err = NPN_PostURL(instance, instanceData->testUrl.c_str(),
  1284       instanceData->postMode == POSTMODE_FRAME ? instanceData->frame.c_str() : nullptr,
  1285       instanceData->streamBufSize,
  1286       reinterpret_cast<char *>(instanceData->streamBuf), false);
  1287     if (err != NPERR_NO_ERROR)
  1288       instanceData->err << "Error: NPN_PostURL returned error value " << err;
  1290   return NPERR_NO_ERROR;
  1293 int32_t
  1294 NPP_WriteReady(NPP instance, NPStream* stream)
  1296   printf("NPP_WriteReady\n");
  1297   InstanceData* instanceData = (InstanceData*)(instance->pdata);
  1298   instanceData->writeReadyCount++;
  1299   if (instanceData->functionToFail == FUNCTION_NPP_NEWSTREAM) {
  1300     instanceData->err << "NPP_WriteReady called";
  1303   // temporarily disabled per bug 519870
  1304   //if (instanceData->writeReadyCount == 1) {
  1305   //  return 0;
  1306   //}
  1308   return instanceData->streamChunkSize;
  1311 int32_t
  1312 NPP_Write(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer)
  1314   InstanceData* instanceData = (InstanceData*)(instance->pdata);
  1315   instanceData->writeCount++;
  1317   // temporarily disabled per bug 519870
  1318   //if (instanceData->writeReadyCount == 1) {
  1319   //  instanceData->err << "NPP_Write called even though NPP_WriteReady " <<
  1320   //      "returned 0";
  1321   //}
  1323   if (instanceData->functionToFail == FUNCTION_NPP_WRITE_RPC) {
  1324     // Make an RPC call and pretend to consume the data
  1325     NPObject* windowObject = nullptr;
  1326     NPN_GetValue(instance, NPNVWindowNPObject, &windowObject);
  1327     if (windowObject)
  1328       NPN_ReleaseObject(windowObject);
  1330     return len;
  1333   if (instanceData->functionToFail == FUNCTION_NPP_NEWSTREAM) {
  1334     instanceData->err << "NPP_Write called";
  1337   if (instanceData->functionToFail == FUNCTION_NPP_WRITE) {
  1338     return -1;
  1341   URLNotifyData* nd = static_cast<URLNotifyData*>(stream->notifyData);
  1343   if (nd && nd->writeCallback) {
  1344     NPVariant args[1];
  1345     STRINGN_TO_NPVARIANT(stream->url, strlen(stream->url), args[0]);
  1347     NPVariant result;
  1348     NPN_InvokeDefault(instance, nd->writeCallback, args, 1, &result);
  1349     NPN_ReleaseVariantValue(&result);
  1352   if (nd && nd != &kNotifyData) {
  1353     uint32_t newsize = nd->size + len;
  1354     nd->data = (char*) realloc(nd->data, newsize);
  1355     memcpy(nd->data + nd->size, buffer, len);
  1356     nd->size = newsize;
  1357     return len;
  1360   if (instanceData->closeStream) {
  1361     instanceData->closeStream = false;
  1362     if (instanceData->testrange != nullptr) {
  1363       NPN_RequestRead(stream, instanceData->testrange);
  1365     NPN_DestroyStream(instance, stream, NPRES_USER_BREAK);
  1367   else if (instanceData->streamMode == NP_SEEK &&
  1368       stream->end != 0 &&
  1369       stream->end == ((uint32_t)instanceData->streamBufSize + len)) {
  1370     // If the complete stream has been written, and we're doing a seek test,
  1371     // then call NPN_RequestRead.
  1372     // prevent recursion
  1373     instanceData->streamMode = NP_NORMAL;
  1375     if (instanceData->testrange != nullptr) {
  1376       NPError err = NPN_RequestRead(stream, instanceData->testrange);
  1377       if (err != NPERR_NO_ERROR) {
  1378         instanceData->err << "NPN_RequestRead returned error %d" << err;
  1380       printf("called NPN_RequestRead, return %d\n", err);
  1384   char* streamBuf = reinterpret_cast<char *>(instanceData->streamBuf);
  1385   if (offset + len <= instanceData->streamBufSize) {
  1386     if (memcmp(buffer, streamBuf + offset, len)) {
  1387       instanceData->err <<
  1388           "Error: data written from NPN_RequestRead doesn't match";
  1390     else {
  1391       printf("data matches!\n");
  1393     TestRange* range = instanceData->testrange;
  1394     bool stillwaiting = false;
  1395     while(range != nullptr) {
  1396       if (offset == range->offset &&
  1397         (uint32_t)len == range->length) {
  1398         range->waiting = false;
  1400       if (range->waiting) stillwaiting = true;
  1401       range = reinterpret_cast<TestRange*>(range->next);
  1403     if (!stillwaiting) {
  1404       NPError err = NPN_DestroyStream(instance, stream, NPRES_DONE);
  1405       if (err != NPERR_NO_ERROR) {
  1406         instanceData->err << "Error: NPN_DestroyStream returned " << err;
  1410   else {
  1411     if (instanceData->streamBufSize == 0) {
  1412       instanceData->streamBuf = malloc(len + 1);
  1413       streamBuf = reinterpret_cast<char *>(instanceData->streamBuf);
  1415     else {
  1416       instanceData->streamBuf =
  1417         realloc(reinterpret_cast<char *>(instanceData->streamBuf),
  1418         instanceData->streamBufSize + len + 1);
  1419       streamBuf = reinterpret_cast<char *>(instanceData->streamBuf);
  1421     memcpy(streamBuf + instanceData->streamBufSize, buffer, len);
  1422     instanceData->streamBufSize = instanceData->streamBufSize + len;
  1423     streamBuf[instanceData->streamBufSize] = '\0';
  1425   return len;
  1428 void
  1429 NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname)
  1431   printf("NPP_StreamAsFile, file=%s\n", fname);
  1432   size_t size;
  1434   InstanceData* instanceData = (InstanceData*)(instance->pdata);
  1436   if (instanceData->functionToFail == FUNCTION_NPP_NEWSTREAM ||
  1437       instanceData->functionToFail == FUNCTION_NPP_WRITE) {
  1438     instanceData->err << "NPP_StreamAsFile called";
  1441   if (!fname)
  1442     return;
  1444   FILE *file = fopen(fname, "rb");
  1445   if (file) {
  1446     fseek(file, 0, SEEK_END);
  1447     size = ftell(file);
  1448     instanceData->fileBuf = malloc((int32_t)size + 1);
  1449     char* buf = reinterpret_cast<char *>(instanceData->fileBuf);
  1450     fseek(file, 0, SEEK_SET);
  1451     size_t sizeRead = fread(instanceData->fileBuf, 1, size, file);
  1452     if (sizeRead != size) {
  1453       printf("Unable to read data from file\n");
  1454       instanceData->err << "Unable to read data from file " << fname;
  1456     fclose(file);
  1457     buf[size] = '\0';
  1458     instanceData->fileBufSize = (int32_t)size;
  1460   else {
  1461     printf("Unable to open file\n");
  1462     instanceData->err << "Unable to open file " << fname;
  1466 void
  1467 NPP_Print(NPP instance, NPPrint* platformPrint)
  1471 int16_t
  1472 NPP_HandleEvent(NPP instance, void* event)
  1474   InstanceData* instanceData = (InstanceData*)(instance->pdata);
  1475   return pluginHandleEvent(instanceData, event);
  1478 void
  1479 NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData)
  1481   InstanceData* instanceData = (InstanceData*)(instance->pdata);
  1482   URLNotifyData* ndata = static_cast<URLNotifyData*>(notifyData);
  1484   printf("NPP_URLNotify called\n");
  1485   if (&kNotifyData == ndata) {
  1486     if (instanceData->frame.length() > 0) {
  1487       sendBufferToFrame(instance);
  1490   else if (!strcmp(ndata->cookie, "dynamic-cookie")) {
  1491     if (ndata->notifyCallback) {
  1492       NPVariant args[2];
  1493       INT32_TO_NPVARIANT(reason, args[0]);
  1494       if (ndata->data) {
  1495         STRINGN_TO_NPVARIANT(ndata->data, ndata->size, args[1]);
  1497       else {
  1498         STRINGN_TO_NPVARIANT("", 0, args[1]);
  1501       NPVariant result;
  1502       NPN_InvokeDefault(instance, ndata->notifyCallback, args, 2, &result);
  1503       NPN_ReleaseVariantValue(&result);
  1506     // clean up the URLNotifyData
  1507     if (ndata->writeCallback) {
  1508       NPN_ReleaseObject(ndata->writeCallback);
  1510     if (ndata->notifyCallback) {
  1511       NPN_ReleaseObject(ndata->notifyCallback);
  1513     if (ndata->redirectCallback) {
  1514       NPN_ReleaseObject(ndata->redirectCallback);
  1516     free(ndata->data);
  1517     delete ndata;
  1519   else {
  1520     printf("ERROR! NPP_URLNotify called with wrong cookie\n");
  1521     instanceData->err << "Error: NPP_URLNotify called with wrong cookie";
  1525 NPError
  1526 NPP_GetValue(NPP instance, NPPVariable variable, void* value)
  1528   InstanceData* instanceData = (InstanceData*)instance->pdata;
  1529   if (variable == NPPVpluginScriptableNPObject) {
  1530     NPObject* object = instanceData->scriptableObject;
  1531     NPN_RetainObject(object);
  1532     *((NPObject**)value) = object;
  1533     return NPERR_NO_ERROR;
  1535   if (variable == NPPVpluginNeedsXEmbed) {
  1536     // Only relevant for X plugins
  1537     // use 4-byte writes like some plugins may do
  1538     *(uint32_t*)value = instanceData->hasWidget;
  1539     return NPERR_NO_ERROR;
  1541   if (variable == NPPVpluginWantsAllNetworkStreams) {
  1542     // use 4-byte writes like some plugins may do
  1543     *(uint32_t*)value = instanceData->wantsAllStreams;
  1544     return NPERR_NO_ERROR;
  1547   return NPERR_GENERIC_ERROR;
  1550 NPError
  1551 NPP_SetValue(NPP instance, NPNVariable variable, void* value)
  1553   if (variable == NPNVprivateModeBool) {
  1554     InstanceData* instanceData = (InstanceData*)(instance->pdata);
  1555     instanceData->lastReportedPrivateModeState = bool(*static_cast<NPBool*>(value));
  1556     return NPERR_NO_ERROR;
  1558   return NPERR_GENERIC_ERROR;
  1561 void
  1562 NPP_URLRedirectNotify(NPP instance, const char* url, int32_t status, void* notifyData)
  1564   if (notifyData) {
  1565     URLNotifyData* nd = static_cast<URLNotifyData*>(notifyData);
  1566     if (nd->redirectCallback) {
  1567       NPVariant args[2];
  1568       STRINGN_TO_NPVARIANT(url, strlen(url), args[0]);
  1569       INT32_TO_NPVARIANT(status, args[1]);
  1571       NPVariant result;
  1572       NPN_InvokeDefault(instance, nd->redirectCallback, args, 2, &result);
  1573       NPN_ReleaseVariantValue(&result);
  1575     NPN_URLRedirectResponse(instance, notifyData, nd->allowRedirects);
  1576     return;
  1578   NPN_URLRedirectResponse(instance, notifyData, true);
  1581 NPError
  1582 NPP_ClearSiteData(const char* site, uint64_t flags, uint64_t maxAge)
  1584   if (!sSitesWithData)
  1585     return NPERR_NO_ERROR;
  1587   // Error condition: no support for clear-by-age
  1588   if (!sClearByAgeSupported && maxAge != uint64_t(int64_t(-1)))
  1589     return NPERR_TIME_RANGE_NOT_SUPPORTED;
  1591   // Iterate over list and remove matches
  1592   list<siteData>::iterator iter = sSitesWithData->begin();
  1593   list<siteData>::iterator end = sSitesWithData->end();
  1594   while (iter != end) {
  1595     const siteData& data = *iter;
  1596     list<siteData>::iterator next = iter;
  1597     ++next;
  1598     if ((!site || data.site.compare(site) == 0) &&
  1599         (flags == NP_CLEAR_ALL || data.flags & flags) &&
  1600         data.age <= maxAge) {
  1601       sSitesWithData->erase(iter);
  1603     iter = next;
  1606   return NPERR_NO_ERROR;
  1609 char**
  1610 NPP_GetSitesWithData()
  1612   int length = 0;
  1613   char** result;
  1615   if (sSitesWithData)
  1616     length = sSitesWithData->size();
  1618   // Allocate the maximum possible size the list could be.
  1619   result = static_cast<char**>(NPN_MemAlloc((length + 1) * sizeof(char*)));
  1620   result[length] = nullptr;
  1622   if (length == 0) {
  1623     // Represent the no site data case as an array of length 1 with a nullptr
  1624     // entry.
  1625     return result;
  1628   // Iterate the list of stored data, and build a list of strings.
  1629   list<string> sites;
  1631     list<siteData>::iterator iter = sSitesWithData->begin();
  1632     list<siteData>::iterator end = sSitesWithData->end();
  1633     for (; iter != end; ++iter) {
  1634       const siteData& data = *iter;
  1635       sites.push_back(data.site);
  1639   // Remove duplicate strings.
  1640   sites.sort();
  1641   sites.unique();
  1643   // Add strings to the result array, and null terminate.
  1645     int i = 0;
  1646     list<string>::iterator iter = sites.begin();
  1647     list<string>::iterator end = sites.end();
  1648     for (; iter != end; ++iter, ++i) {
  1649       const string& site = *iter;
  1650       result[i] = static_cast<char*>(NPN_MemAlloc(site.length() + 1));
  1651       memcpy(result[i], site.c_str(), site.length() + 1);
  1654   result[sites.size()] = nullptr;
  1656   return result;
  1659 //
  1660 // npapi browser functions
  1661 //
  1663 bool
  1664 NPN_SetProperty(NPP instance, NPObject* obj, NPIdentifier propertyName, const NPVariant* value)
  1666   return sBrowserFuncs->setproperty(instance, obj, propertyName, value);
  1669 NPIdentifier
  1670 NPN_GetIntIdentifier(int32_t intid)
  1672   return sBrowserFuncs->getintidentifier(intid);
  1675 NPIdentifier
  1676 NPN_GetStringIdentifier(const NPUTF8* name)
  1678   return sBrowserFuncs->getstringidentifier(name);
  1681 void
  1682 NPN_GetStringIdentifiers(const NPUTF8 **names, int32_t nameCount, NPIdentifier *identifiers)
  1684   return sBrowserFuncs->getstringidentifiers(names, nameCount, identifiers);
  1687 bool
  1688 NPN_IdentifierIsString(NPIdentifier identifier)
  1690   return sBrowserFuncs->identifierisstring(identifier);
  1693 NPUTF8*
  1694 NPN_UTF8FromIdentifier(NPIdentifier identifier)
  1696   return sBrowserFuncs->utf8fromidentifier(identifier);
  1699 int32_t
  1700 NPN_IntFromIdentifier(NPIdentifier identifier)
  1702   return sBrowserFuncs->intfromidentifier(identifier);
  1705 NPError
  1706 NPN_GetValue(NPP instance, NPNVariable variable, void* value)
  1708   return sBrowserFuncs->getvalue(instance, variable, value);
  1711 NPError
  1712 NPN_SetValue(NPP instance, NPPVariable variable, void* value)
  1714   return sBrowserFuncs->setvalue(instance, variable, value);
  1717 void
  1718 NPN_InvalidateRect(NPP instance, NPRect* rect)
  1720   sBrowserFuncs->invalidaterect(instance, rect);
  1723 bool
  1724 NPN_HasProperty(NPP instance, NPObject* obj, NPIdentifier propertyName)
  1726   return sBrowserFuncs->hasproperty(instance, obj, propertyName);
  1729 NPObject*
  1730 NPN_CreateObject(NPP instance, NPClass* aClass)
  1732   return sBrowserFuncs->createobject(instance, aClass);
  1735 bool
  1736 NPN_Invoke(NPP npp, NPObject* obj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result)
  1738   return sBrowserFuncs->invoke(npp, obj, methodName, args, argCount, result);
  1741 bool
  1742 NPN_InvokeDefault(NPP npp, NPObject* obj, const NPVariant *args, uint32_t argCount, NPVariant *result)
  1744   return sBrowserFuncs->invokeDefault(npp, obj, args, argCount, result);
  1747 bool
  1748 NPN_Construct(NPP npp, NPObject* npobj, const NPVariant* args,
  1749 	      uint32_t argCount, NPVariant* result)
  1751   return sBrowserFuncs->construct(npp, npobj, args, argCount, result);
  1754 const char*
  1755 NPN_UserAgent(NPP instance)
  1757   return sBrowserFuncs->uagent(instance);
  1760 NPObject*
  1761 NPN_RetainObject(NPObject* obj)
  1763   return sBrowserFuncs->retainobject(obj);
  1766 void
  1767 NPN_ReleaseObject(NPObject* obj)
  1769   return sBrowserFuncs->releaseobject(obj);
  1772 void*
  1773 NPN_MemAlloc(uint32_t size)
  1775   return sBrowserFuncs->memalloc(size);
  1778 char*
  1779 NPN_StrDup(const char* str)
  1781   return strcpy((char*)sBrowserFuncs->memalloc(strlen(str) + 1), str);
  1784 void
  1785 NPN_MemFree(void* ptr)
  1787   return sBrowserFuncs->memfree(ptr);
  1790 uint32_t
  1791 NPN_ScheduleTimer(NPP instance, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID))
  1793   return sBrowserFuncs->scheduletimer(instance, interval, repeat, timerFunc);
  1796 void
  1797 NPN_UnscheduleTimer(NPP instance, uint32_t timerID)
  1799   return sBrowserFuncs->unscheduletimer(instance, timerID);
  1802 void
  1803 NPN_ReleaseVariantValue(NPVariant *variant)
  1805   return sBrowserFuncs->releasevariantvalue(variant);
  1808 NPError
  1809 NPN_GetURLNotify(NPP instance, const char* url, const char* target, void* notifyData)
  1811   return sBrowserFuncs->geturlnotify(instance, url, target, notifyData);
  1814 NPError
  1815 NPN_GetURL(NPP instance, const char* url, const char* target)
  1817   return sBrowserFuncs->geturl(instance, url, target);
  1820 NPError
  1821 NPN_RequestRead(NPStream* stream, NPByteRange* rangeList)
  1823   return sBrowserFuncs->requestread(stream, rangeList);
  1826 NPError
  1827 NPN_PostURLNotify(NPP instance, const char* url,
  1828                   const char* target, uint32_t len,
  1829                   const char* buf, NPBool file, void* notifyData)
  1831   return sBrowserFuncs->posturlnotify(instance, url, target, len, buf, file, notifyData);
  1834 NPError
  1835 NPN_PostURL(NPP instance, const char *url,
  1836                     const char *target, uint32_t len,
  1837                     const char *buf, NPBool file)
  1839   return sBrowserFuncs->posturl(instance, url, target, len, buf, file);
  1842 NPError
  1843 NPN_DestroyStream(NPP instance, NPStream* stream, NPError reason)
  1845   return sBrowserFuncs->destroystream(instance, stream, reason);
  1848 NPError
  1849 NPN_NewStream(NPP instance,
  1850               NPMIMEType  type,
  1851               const char* target,
  1852               NPStream**  stream)
  1854   return sBrowserFuncs->newstream(instance, type, target, stream);
  1857 int32_t
  1858 NPN_Write(NPP instance,
  1859           NPStream* stream,
  1860           int32_t len,
  1861           void* buf)
  1863   return sBrowserFuncs->write(instance, stream, len, buf);
  1866 bool
  1867 NPN_Enumerate(NPP instance,
  1868               NPObject *npobj,
  1869               NPIdentifier **identifiers,
  1870               uint32_t *identifierCount)
  1872   return sBrowserFuncs->enumerate(instance, npobj, identifiers,
  1873       identifierCount);
  1876 bool
  1877 NPN_GetProperty(NPP instance,
  1878                 NPObject *npobj,
  1879                 NPIdentifier propertyName,
  1880                 NPVariant *result)
  1882   return sBrowserFuncs->getproperty(instance, npobj, propertyName, result);
  1885 bool
  1886 NPN_Evaluate(NPP instance, NPObject *npobj, NPString *script, NPVariant *result)
  1888   return sBrowserFuncs->evaluate(instance, npobj, script, result);
  1891 void
  1892 NPN_SetException(NPObject *npobj, const NPUTF8 *message)
  1894   return sBrowserFuncs->setexception(npobj, message);
  1897 NPBool
  1898 NPN_ConvertPoint(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace)
  1900   return sBrowserFuncs->convertpoint(instance, sourceX, sourceY, sourceSpace, destX, destY, destSpace);
  1903 NPError
  1904 NPN_SetValueForURL(NPP instance, NPNURLVariable variable, const char *url, const char *value, uint32_t len)
  1906   return sBrowserFuncs->setvalueforurl(instance, variable, url, value, len);
  1909 NPError
  1910 NPN_GetValueForURL(NPP instance, NPNURLVariable variable, const char *url, char **value, uint32_t *len)
  1912   return sBrowserFuncs->getvalueforurl(instance, variable, url, value, len);
  1915 NPError
  1916 NPN_GetAuthenticationInfo(NPP instance,
  1917                           const char *protocol,
  1918                           const char *host, int32_t port,
  1919                           const char *scheme,
  1920                           const char *realm,
  1921                           char **username, uint32_t *ulen,
  1922                           char **password,
  1923                           uint32_t *plen)
  1925   return sBrowserFuncs->getauthenticationinfo(instance, protocol, host, port, scheme, realm,
  1926       username, ulen, password, plen);
  1929 void
  1930 NPN_PluginThreadAsyncCall(NPP plugin, void (*func)(void*), void* userdata)
  1932   return sBrowserFuncs->pluginthreadasynccall(plugin, func, userdata);
  1935 void
  1936 NPN_URLRedirectResponse(NPP instance, void* notifyData, NPBool allow)
  1938   return sBrowserFuncs->urlredirectresponse(instance, notifyData, allow);
  1941 NPError
  1942 NPN_InitAsyncSurface(NPP instance, NPSize *size, NPImageFormat format,
  1943                      void *initData, NPAsyncSurface *surface)
  1945   return sBrowserFuncs->initasyncsurface(instance, size, format, initData, surface);
  1948 NPError
  1949 NPN_FinalizeAsyncSurface(NPP instance, NPAsyncSurface *surface)
  1951   return sBrowserFuncs->finalizeasyncsurface(instance, surface);
  1954 void
  1955 NPN_SetCurrentAsyncSurface(NPP instance, NPAsyncSurface *surface, NPRect *changed)
  1957   sBrowserFuncs->setcurrentasyncsurface(instance, surface, changed);
  1960 //
  1961 // npruntime object functions
  1962 //
  1964 NPObject*
  1965 scriptableAllocate(NPP npp, NPClass* aClass)
  1967   TestNPObject* object = (TestNPObject*)NPN_MemAlloc(sizeof(TestNPObject));
  1968   if (!object)
  1969     return nullptr;
  1970   memset(object, 0, sizeof(TestNPObject));
  1971   return object;
  1974 void
  1975 scriptableDeallocate(NPObject* npobj)
  1977   NPN_MemFree(npobj);
  1980 void
  1981 scriptableInvalidate(NPObject* npobj)
  1985 bool
  1986 scriptableHasMethod(NPObject* npobj, NPIdentifier name)
  1988   for (int i = 0; i < int(ARRAY_LENGTH(sPluginMethodIdentifiers)); i++) {
  1989     if (name == sPluginMethodIdentifiers[i])
  1990       return true;
  1992   return false;
  1995 bool
  1996 scriptableInvoke(NPObject* npobj, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result)
  1998   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  1999   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  2000   if (id->throwOnNextInvoke) {
  2001     id->throwOnNextInvoke = false;
  2002     if (argCount == 0) {
  2003       NPN_SetException(npobj, nullptr);
  2005     else {
  2006       for (uint32_t i = 0; i < argCount; i++) {
  2007         const NPString* argstr = &NPVARIANT_TO_STRING(args[i]);
  2008         NPN_SetException(npobj, argstr->UTF8Characters);
  2011     return false;
  2014   for (int i = 0; i < int(ARRAY_LENGTH(sPluginMethodIdentifiers)); i++) {
  2015     if (name == sPluginMethodIdentifiers[i])
  2016       return sPluginMethodFunctions[i](npobj, args, argCount, result);
  2018   return false;
  2021 bool
  2022 scriptableInvokeDefault(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2024   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  2025   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  2026   if (id->throwOnNextInvoke) {
  2027     id->throwOnNextInvoke = false;
  2028     if (argCount == 0) {
  2029       NPN_SetException(npobj, nullptr);
  2031     else {
  2032       for (uint32_t i = 0; i < argCount; i++) {
  2033         const NPString* argstr = &NPVARIANT_TO_STRING(args[i]);
  2034         NPN_SetException(npobj, argstr->UTF8Characters);
  2037     return false;
  2040   ostringstream value;
  2041   value << sPluginName;
  2042   for (uint32_t i = 0; i < argCount; i++) {
  2043     switch(args[i].type) {
  2044       case NPVariantType_Int32:
  2045         value << ";" << NPVARIANT_TO_INT32(args[i]);
  2046         break;
  2047       case NPVariantType_String: {
  2048         const NPString* argstr = &NPVARIANT_TO_STRING(args[i]);
  2049         value << ";" << argstr->UTF8Characters;
  2050         break;
  2052       case NPVariantType_Void:
  2053         value << ";undefined";
  2054         break;
  2055       case NPVariantType_Null:
  2056         value << ";null";
  2057         break;
  2058       default:
  2059         value << ";other";
  2063   char *outval = NPN_StrDup(value.str().c_str());
  2064   STRINGZ_TO_NPVARIANT(outval, *result);
  2065   return true;
  2068 bool
  2069 scriptableHasProperty(NPObject* npobj, NPIdentifier name)
  2071   if (NPN_IdentifierIsString(name)) {
  2072     NPUTF8 *asUTF8 = NPN_UTF8FromIdentifier(name);
  2073     if (NPN_GetStringIdentifier(asUTF8) != name) {
  2074       Crash();
  2076     NPN_MemFree(asUTF8);
  2078   else {
  2079     if (NPN_GetIntIdentifier(NPN_IntFromIdentifier(name)) != name) {
  2080       Crash();
  2083   for (int i = 0; i < int(ARRAY_LENGTH(sPluginPropertyIdentifiers)); i++) {
  2084     if (name == sPluginPropertyIdentifiers[i]) {
  2085       return true;
  2088   return false;
  2091 bool
  2092 scriptableGetProperty(NPObject* npobj, NPIdentifier name, NPVariant* result)
  2094   for (int i = 0; i < int(ARRAY_LENGTH(sPluginPropertyIdentifiers)); i++) {
  2095     if (name == sPluginPropertyIdentifiers[i]) {
  2096       DuplicateNPVariant(*result, sPluginPropertyValues[i]);
  2097       return true;
  2100   return false;
  2103 bool
  2104 scriptableSetProperty(NPObject* npobj, NPIdentifier name, const NPVariant* value)
  2106   for (int i = 0; i < int(ARRAY_LENGTH(sPluginPropertyIdentifiers)); i++) {
  2107     if (name == sPluginPropertyIdentifiers[i]) {
  2108       NPN_ReleaseVariantValue(&sPluginPropertyValues[i]);
  2109       DuplicateNPVariant(sPluginPropertyValues[i], *value);
  2110       return true;
  2113   return false;
  2116 bool
  2117 scriptableRemoveProperty(NPObject* npobj, NPIdentifier name)
  2119   for (int i = 0; i < int(ARRAY_LENGTH(sPluginPropertyIdentifiers)); i++) {
  2120     if (name == sPluginPropertyIdentifiers[i]) {
  2121       NPN_ReleaseVariantValue(&sPluginPropertyValues[i]);
  2122       return true;
  2125   return false;
  2128 bool
  2129 scriptableEnumerate(NPObject* npobj, NPIdentifier** identifier, uint32_t* count)
  2131   const int bufsize = sizeof(NPIdentifier) * ARRAY_LENGTH(sPluginMethodIdentifierNames);
  2132   NPIdentifier* ids = (NPIdentifier*) NPN_MemAlloc(bufsize);
  2133   if (!ids)
  2134     return false;
  2136   memcpy(ids, sPluginMethodIdentifiers, bufsize);
  2137   *identifier = ids;
  2138   *count = ARRAY_LENGTH(sPluginMethodIdentifierNames);
  2139   return true;
  2142 bool
  2143 scriptableConstruct(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2145   return false;
  2148 //
  2149 // test functions
  2150 //
  2152 static bool
  2153 compareVariants(NPP instance, const NPVariant* var1, const NPVariant* var2)
  2155   bool success = true;
  2156   InstanceData* id = static_cast<InstanceData*>(instance->pdata);
  2157   if (var1->type != var2->type) {
  2158     id->err << "Variant types don't match; got " << var1->type <<
  2159         " expected " << var2->type;
  2160     return false;
  2163   switch (var1->type) {
  2164     case NPVariantType_Int32: {
  2165         int32_t result = NPVARIANT_TO_INT32(*var1);
  2166         int32_t expected = NPVARIANT_TO_INT32(*var2);
  2167         if (result != expected) {
  2168           id->err << "Variant values don't match; got " << result <<
  2169               " expected " << expected;
  2170           success = false;
  2172         break;
  2174     case NPVariantType_Double: {
  2175         double result = NPVARIANT_TO_DOUBLE(*var1);
  2176         double expected = NPVARIANT_TO_DOUBLE(*var2);
  2177         if (result != expected) {
  2178           id->err << "Variant values don't match (double)";
  2179           success = false;
  2181         break;
  2183     case NPVariantType_Void: {
  2184         // void values are always equivalent
  2185         break;
  2187     case NPVariantType_Null: {
  2188         // null values are always equivalent
  2189         break;
  2191     case NPVariantType_Bool: {
  2192         bool result = NPVARIANT_TO_BOOLEAN(*var1);
  2193         bool expected = NPVARIANT_TO_BOOLEAN(*var2);
  2194         if (result != expected) {
  2195           id->err << "Variant values don't match (bool)";
  2196           success = false;
  2198         break;
  2200     case NPVariantType_String: {
  2201         const NPString* result = &NPVARIANT_TO_STRING(*var1);
  2202         const NPString* expected = &NPVARIANT_TO_STRING(*var2);
  2203         if (strcmp(result->UTF8Characters, expected->UTF8Characters) ||
  2204             strlen(result->UTF8Characters) != strlen(expected->UTF8Characters)) {
  2205           id->err << "Variant values don't match; got " <<
  2206               result->UTF8Characters << " expected " <<
  2207               expected->UTF8Characters;
  2208           success = false;
  2210         break;
  2212     case NPVariantType_Object: {
  2213         uint32_t i, identifierCount = 0;
  2214         NPIdentifier* identifiers;
  2215         NPObject* result = NPVARIANT_TO_OBJECT(*var1);
  2216         NPObject* expected = NPVARIANT_TO_OBJECT(*var2);
  2217         bool enumerate_result = NPN_Enumerate(instance, expected,
  2218             &identifiers, &identifierCount);
  2219         if (!enumerate_result) {
  2220           id->err << "NPN_Enumerate failed";
  2221           success = false;
  2223         for (i = 0; i < identifierCount; i++) {
  2224           NPVariant resultVariant, expectedVariant;
  2225           if (!NPN_GetProperty(instance, expected, identifiers[i],
  2226               &expectedVariant)) {
  2227             id->err << "NPN_GetProperty returned false";
  2228             success = false;
  2230           else {
  2231             if (!NPN_HasProperty(instance, result, identifiers[i])) {
  2232               id->err << "NPN_HasProperty returned false";
  2233               success = false;
  2235             else {
  2236               if (!NPN_GetProperty(instance, result, identifiers[i],
  2237               &resultVariant)) {
  2238                 id->err << "NPN_GetProperty 2 returned false";
  2239                 success = false;
  2241               else {
  2242                 success = compareVariants(instance, &resultVariant,
  2243                     &expectedVariant);
  2244                 NPN_ReleaseVariantValue(&expectedVariant);
  2247             NPN_ReleaseVariantValue(&resultVariant);
  2250         break;
  2252     default:
  2253       id->err << "Unknown variant type";
  2254       success = false;
  2257   return success;
  2260 static bool
  2261 throwExceptionNextInvoke(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2263   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  2264   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  2265   id->throwOnNextInvoke = true;
  2266   BOOLEAN_TO_NPVARIANT(true, *result);
  2267   return true;
  2270 static bool
  2271 npnInvokeDefaultTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2273   bool success = false;
  2274   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  2276   NPObject* windowObject;
  2277   NPN_GetValue(npp, NPNVWindowNPObject, &windowObject);
  2278   if (!windowObject)
  2279     return false;
  2281   NPIdentifier objectIdentifier = variantToIdentifier(args[0]);
  2282   if (!objectIdentifier)
  2283     return false;
  2285   NPVariant objectVariant;
  2286   if (NPN_GetProperty(npp, windowObject, objectIdentifier,
  2287       &objectVariant)) {
  2288     if (NPVARIANT_IS_OBJECT(objectVariant)) {
  2289       NPObject* selfObject = NPVARIANT_TO_OBJECT(objectVariant);
  2290       if (selfObject != nullptr) {
  2291         NPVariant resultVariant;
  2292         if (NPN_InvokeDefault(npp, selfObject, argCount > 1 ? &args[1] : nullptr,
  2293             argCount - 1, &resultVariant)) {
  2294           *result = resultVariant;
  2295           success = true;
  2299     NPN_ReleaseVariantValue(&objectVariant);
  2302   NPN_ReleaseObject(windowObject);
  2303   return success;
  2306 static bool
  2307 npnInvokeTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2309   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  2310   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  2311   id->err.str("");
  2312   if (argCount < 2)
  2313     return false;
  2315   NPIdentifier function = variantToIdentifier(args[0]);
  2316   if (!function)
  2317     return false;
  2319   NPObject* windowObject;
  2320   NPN_GetValue(npp, NPNVWindowNPObject, &windowObject);
  2321   if (!windowObject)
  2322     return false;
  2324   NPVariant invokeResult;
  2325   bool invokeReturn = NPN_Invoke(npp, windowObject, function,
  2326       argCount > 2 ? &args[2] : nullptr, argCount - 2, &invokeResult);
  2328   bool compareResult = compareVariants(npp, &invokeResult, &args[1]);
  2330   NPN_ReleaseObject(windowObject);
  2331   NPN_ReleaseVariantValue(&invokeResult);
  2332   BOOLEAN_TO_NPVARIANT(invokeReturn && compareResult, *result);
  2333   return true;
  2336 static bool
  2337 npnEvaluateTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2339   bool success = false;
  2340   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  2342   if (argCount != 1)
  2343     return false;
  2345   if (!NPVARIANT_IS_STRING(args[0]))
  2346     return false;
  2348   NPObject* windowObject;
  2349   NPN_GetValue(npp, NPNVWindowNPObject, &windowObject);
  2350   if (!windowObject)
  2351     return false;
  2353   success = NPN_Evaluate(npp, windowObject, (NPString*)&NPVARIANT_TO_STRING(args[0]), result);
  2355   NPN_ReleaseObject(windowObject);
  2356   return success;
  2359 static bool
  2360 setUndefinedValueTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2362   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  2363   NPError err = NPN_SetValue(npp, (NPPVariable)0x0, 0x0);
  2364   BOOLEAN_TO_NPVARIANT((err == NPERR_NO_ERROR), *result);
  2365   return true;
  2368 static bool
  2369 identifierToStringTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2371   if (argCount != 1)
  2372     return false;
  2373   NPIdentifier identifier = variantToIdentifier(args[0]);
  2374   if (!identifier)
  2375     return false;
  2377   NPUTF8* utf8String = NPN_UTF8FromIdentifier(identifier);
  2378   if (!utf8String)
  2379     return false;
  2380   STRINGZ_TO_NPVARIANT(utf8String, *result);
  2381   return true;
  2384 static bool
  2385 queryPrivateModeState(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2387   if (argCount != 0)
  2388     return false;
  2390   NPBool pms = false;
  2391   NPN_GetValue(static_cast<TestNPObject*>(npobj)->npp, NPNVprivateModeBool, &pms);
  2392   BOOLEAN_TO_NPVARIANT(pms, *result);
  2393   return true;
  2396 static bool
  2397 lastReportedPrivateModeState(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2399   if (argCount != 0)
  2400     return false;
  2402   InstanceData* id = static_cast<InstanceData*>(static_cast<TestNPObject*>(npobj)->npp->pdata);
  2403   BOOLEAN_TO_NPVARIANT(id->lastReportedPrivateModeState, *result);
  2404   return true;
  2407 static bool
  2408 hasWidget(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2410   if (argCount != 0)
  2411     return false;
  2413   InstanceData* id = static_cast<InstanceData*>(static_cast<TestNPObject*>(npobj)->npp->pdata);
  2414   BOOLEAN_TO_NPVARIANT(id->hasWidget, *result);
  2415   return true;
  2418 static bool
  2419 getEdge(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2421   if (argCount != 1)
  2422     return false;
  2423   if (!NPVARIANT_IS_INT32(args[0]))
  2424     return false;
  2425   int32_t edge = NPVARIANT_TO_INT32(args[0]);
  2426   if (edge < EDGE_LEFT || edge > EDGE_BOTTOM)
  2427     return false;
  2429   InstanceData* id = static_cast<InstanceData*>(static_cast<TestNPObject*>(npobj)->npp->pdata);
  2430   int32_t r = pluginGetEdge(id, RectEdge(edge));
  2431   if (r == NPTEST_INT32_ERROR)
  2432     return false;
  2433   INT32_TO_NPVARIANT(r, *result);
  2434   return true;
  2437 static bool
  2438 getClipRegionRectCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2440   if (argCount != 0)
  2441     return false;
  2443   InstanceData* id = static_cast<InstanceData*>(static_cast<TestNPObject*>(npobj)->npp->pdata);
  2444   int32_t r = pluginGetClipRegionRectCount(id);
  2445   if (r == NPTEST_INT32_ERROR)
  2446     return false;
  2447   INT32_TO_NPVARIANT(r, *result);
  2448   return true;
  2451 static bool
  2452 getClipRegionRectEdge(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2454   if (argCount != 2)
  2455     return false;
  2456   if (!NPVARIANT_IS_INT32(args[0]))
  2457     return false;
  2458   int32_t rectIndex = NPVARIANT_TO_INT32(args[0]);
  2459   if (rectIndex < 0)
  2460     return false;
  2461   if (!NPVARIANT_IS_INT32(args[1]))
  2462     return false;
  2463   int32_t edge = NPVARIANT_TO_INT32(args[1]);
  2464   if (edge < EDGE_LEFT || edge > EDGE_BOTTOM)
  2465     return false;
  2467   InstanceData* id = static_cast<InstanceData*>(static_cast<TestNPObject*>(npobj)->npp->pdata);
  2468   int32_t r = pluginGetClipRegionRectEdge(id, rectIndex, RectEdge(edge));
  2469   if (r == NPTEST_INT32_ERROR)
  2470     return false;
  2471   INT32_TO_NPVARIANT(r, *result);
  2472   return true;
  2475 static bool
  2476 startWatchingInstanceCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2478   if (argCount != 0)
  2479     return false;
  2480   if (sWatchingInstanceCount)
  2481     return false;
  2483   sWatchingInstanceCount = true;
  2484   sInstanceCount = 0;
  2485   ++sCurrentInstanceCountWatchGeneration;
  2486   return true;
  2489 static bool
  2490 getInstanceCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2492   if (argCount != 0)
  2493     return false;
  2494   if (!sWatchingInstanceCount)
  2495     return false;
  2497   INT32_TO_NPVARIANT(sInstanceCount, *result);
  2498   return true;
  2501 static bool
  2502 stopWatchingInstanceCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2504   if (argCount != 0)
  2505     return false;
  2506   if (!sWatchingInstanceCount)
  2507     return false;
  2509   sWatchingInstanceCount = false;
  2510   return true;
  2513 static bool
  2514 getLastMouseX(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2516   if (argCount != 0)
  2517     return false;
  2519   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  2520   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  2521   INT32_TO_NPVARIANT(id->lastMouseX, *result);
  2522   return true;
  2525 static bool
  2526 getLastMouseY(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2528   if (argCount != 0)
  2529     return false;
  2531   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  2532   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  2533   INT32_TO_NPVARIANT(id->lastMouseY, *result);
  2534   return true;
  2537 static bool
  2538 getPaintCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2540   if (argCount != 0)
  2541     return false;
  2543   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  2544   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  2545   INT32_TO_NPVARIANT(id->paintCount, *result);
  2546   return true;
  2549 static bool
  2550 getWidthAtLastPaint(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2552   if (argCount != 0)
  2553     return false;
  2555   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  2556   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  2557   INT32_TO_NPVARIANT(id->widthAtLastPaint, *result);
  2558   return true;
  2561 static bool
  2562 setInvalidateDuringPaint(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2564   if (argCount != 1)
  2565     return false;
  2567   if (!NPVARIANT_IS_BOOLEAN(args[0]))
  2568     return false;
  2569   bool doInvalidate = NPVARIANT_TO_BOOLEAN(args[0]);
  2571   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  2572   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  2573   id->invalidateDuringPaint = doInvalidate;
  2574   return true;
  2577 static bool
  2578 setSlowPaint(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2580   if (argCount != 1)
  2581     return false;
  2583   if (!NPVARIANT_IS_BOOLEAN(args[0]))
  2584     return false;
  2585   bool slow = NPVARIANT_TO_BOOLEAN(args[0]);
  2587   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  2588   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  2589   id->slowPaint = slow;
  2590   return true;
  2593 static bool
  2594 getError(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2596   if (argCount != 0)
  2597     return false;
  2599   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  2600   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  2601   if (id->err.str().length() == 0) {
  2602     char *outval = NPN_StrDup(SUCCESS_STRING);
  2603     STRINGZ_TO_NPVARIANT(outval, *result);
  2604   } else {
  2605     char *outval = NPN_StrDup(id->err.str().c_str());
  2606     STRINGZ_TO_NPVARIANT(outval, *result);
  2608   return true;
  2611 static bool
  2612 doInternalConsistencyCheck(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2614   if (argCount != 0)
  2615     return false;
  2617   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  2618   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  2619   string error;
  2620   pluginDoInternalConsistencyCheck(id, error);
  2621   NPUTF8* utf8String = (NPUTF8*)NPN_MemAlloc(error.length() + 1);
  2622   if (!utf8String) {
  2623     return false;
  2625   memcpy(utf8String, error.c_str(), error.length() + 1);
  2626   STRINGZ_TO_NPVARIANT(utf8String, *result);
  2627   return true;
  2630 static bool
  2631 convertPointX(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2633   if (argCount != 4)
  2634     return false;
  2636   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  2638   if (!NPVARIANT_IS_INT32(args[0]))
  2639     return false;
  2640   int32_t sourceSpace = NPVARIANT_TO_INT32(args[0]);
  2642   if (!NPVARIANT_IS_INT32(args[1]))
  2643     return false;
  2644   double sourceX = static_cast<double>(NPVARIANT_TO_INT32(args[1]));
  2646   if (!NPVARIANT_IS_INT32(args[2]))
  2647     return false;
  2648   double sourceY = static_cast<double>(NPVARIANT_TO_INT32(args[2]));
  2650   if (!NPVARIANT_IS_INT32(args[3]))
  2651     return false;
  2652   int32_t destSpace = NPVARIANT_TO_INT32(args[3]);
  2654   double resultX, resultY;
  2655   NPN_ConvertPoint(npp, sourceX, sourceY, (NPCoordinateSpace)sourceSpace, &resultX, &resultY, (NPCoordinateSpace)destSpace);
  2657   DOUBLE_TO_NPVARIANT(resultX, *result);
  2658   return true;
  2661 static bool
  2662 convertPointY(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2664   if (argCount != 4)
  2665     return false;
  2667   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  2669   if (!NPVARIANT_IS_INT32(args[0]))
  2670     return false;
  2671   int32_t sourceSpace = NPVARIANT_TO_INT32(args[0]);
  2673   if (!NPVARIANT_IS_INT32(args[1]))
  2674     return false;
  2675   double sourceX = static_cast<double>(NPVARIANT_TO_INT32(args[1]));
  2677   if (!NPVARIANT_IS_INT32(args[2]))
  2678     return false;
  2679   double sourceY = static_cast<double>(NPVARIANT_TO_INT32(args[2]));
  2681   if (!NPVARIANT_IS_INT32(args[3]))
  2682     return false;
  2683   int32_t destSpace = NPVARIANT_TO_INT32(args[3]);
  2685   double resultX, resultY;
  2686   NPN_ConvertPoint(npp, sourceX, sourceY, (NPCoordinateSpace)sourceSpace, &resultX, &resultY, (NPCoordinateSpace)destSpace);
  2688   DOUBLE_TO_NPVARIANT(resultY, *result);
  2689   return true;
  2692 static bool
  2693 streamTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2695   // .streamTest(url, doPost, doNull, writeCallback, notifyCallback, redirectCallback, allowRedirects)
  2696   if (7 != argCount)
  2697     return false;
  2699   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  2701   if (!NPVARIANT_IS_STRING(args[0]))
  2702     return false;
  2703   NPString url = NPVARIANT_TO_STRING(args[0]);
  2705   if (!NPVARIANT_IS_BOOLEAN(args[1]))
  2706     return false;
  2707   bool doPost = NPVARIANT_TO_BOOLEAN(args[1]);
  2709   NPString postData = { nullptr, 0 };
  2710   if (NPVARIANT_IS_STRING(args[2])) {
  2711     postData = NPVARIANT_TO_STRING(args[2]);
  2713   else {
  2714     if (!NPVARIANT_IS_NULL(args[2])) {
  2715       return false;
  2719   NPObject* writeCallback = nullptr;
  2720   if (NPVARIANT_IS_OBJECT(args[3])) {
  2721     writeCallback = NPVARIANT_TO_OBJECT(args[3]);
  2723   else {
  2724     if (!NPVARIANT_IS_NULL(args[3])) {
  2725       return false;
  2729   NPObject* notifyCallback = nullptr;
  2730   if (NPVARIANT_IS_OBJECT(args[4])) {
  2731     notifyCallback = NPVARIANT_TO_OBJECT(args[4]);
  2733   else {
  2734     if (!NPVARIANT_IS_NULL(args[4])) {
  2735       return false;
  2739   NPObject* redirectCallback = nullptr;
  2740   if (NPVARIANT_IS_OBJECT(args[5])) {
  2741     redirectCallback = NPVARIANT_TO_OBJECT(args[5]);
  2743   else {
  2744     if (!NPVARIANT_IS_NULL(args[5])) {
  2745       return false;
  2749   if (!NPVARIANT_IS_BOOLEAN(args[6]))
  2750     return false;
  2751   bool allowRedirects = NPVARIANT_TO_BOOLEAN(args[6]);
  2753   URLNotifyData* ndata = new URLNotifyData;
  2754   ndata->cookie = "dynamic-cookie";
  2755   ndata->writeCallback = writeCallback;
  2756   ndata->notifyCallback = notifyCallback;
  2757   ndata->redirectCallback = redirectCallback;
  2758   ndata->size = 0;
  2759   ndata->data = nullptr;
  2760   ndata->allowRedirects = allowRedirects;
  2762   /* null-terminate "url" */
  2763   char* urlstr = (char*) malloc(url.UTF8Length + 1);
  2764   strncpy(urlstr, url.UTF8Characters, url.UTF8Length);
  2765   urlstr[url.UTF8Length] = '\0';
  2767   NPError err;
  2768   if (doPost) {
  2769     err = NPN_PostURLNotify(npp, urlstr, nullptr,
  2770                             postData.UTF8Length, postData.UTF8Characters,
  2771                             false, ndata);
  2773   else {
  2774     err = NPN_GetURLNotify(npp, urlstr, nullptr, ndata);
  2777   free(urlstr);
  2779   if (NPERR_NO_ERROR == err) {
  2780     if (ndata->writeCallback) {
  2781       NPN_RetainObject(ndata->writeCallback);
  2783     if (ndata->notifyCallback) {
  2784       NPN_RetainObject(ndata->notifyCallback);
  2786     if (ndata->redirectCallback) {
  2787       NPN_RetainObject(ndata->redirectCallback);
  2789     BOOLEAN_TO_NPVARIANT(true, *result);
  2791   else {
  2792     delete ndata;
  2793     BOOLEAN_TO_NPVARIANT(false, *result);
  2796   return true;
  2799 static bool
  2800 setPluginWantsAllStreams(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2802   if (1 != argCount)
  2803     return false;
  2805   if (!NPVARIANT_IS_BOOLEAN(args[0]))
  2806     return false;
  2807   bool wantsAllStreams = NPVARIANT_TO_BOOLEAN(args[0]);
  2809   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  2810   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  2812   id->wantsAllStreams = wantsAllStreams;
  2814   return true;
  2817 static bool
  2818 crashPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2820   IntentionalCrash();
  2821   VOID_TO_NPVARIANT(*result);
  2822   return true;
  2825 static bool
  2826 crashOnDestroy(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2828   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  2829   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  2831   id->crashOnDestroy = true;
  2832   VOID_TO_NPVARIANT(*result);
  2833   return true;
  2836 static bool
  2837 setColor(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2839   if (argCount != 1)
  2840     return false;
  2841   if (!NPVARIANT_IS_STRING(args[0]))
  2842     return false;
  2843   const NPString* str = &NPVARIANT_TO_STRING(args[0]);
  2845   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  2846   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  2848   id->scriptableObject->drawColor =
  2849     parseHexColor(str->UTF8Characters, str->UTF8Length);
  2851   NPRect r;
  2852   r.left = 0;
  2853   r.top = 0;
  2854   r.right = id->window.width;
  2855   r.bottom = id->window.height;
  2856   if (id->asyncDrawing == AD_NONE) {
  2857     NPN_InvalidateRect(npp, &r);
  2858   } else if (id->asyncDrawing == AD_BITMAP) {
  2859     drawAsyncBitmapColor(id);
  2861 #ifdef XP_WIN
  2862   else if (id->asyncDrawing == AD_DXGI) {
  2863     pluginDrawAsyncDxgiColor(id);
  2865 #endif
  2867   VOID_TO_NPVARIANT(*result);
  2868   return true;
  2871 void notifyDidPaint(InstanceData* instanceData)
  2873   ++instanceData->paintCount;
  2874   instanceData->widthAtLastPaint = instanceData->window.width;
  2876   if (instanceData->invalidateDuringPaint) {
  2877     NPRect r;
  2878     r.left = 0;
  2879     r.top = 0;
  2880     r.right = instanceData->window.width;
  2881     r.bottom = instanceData->window.height;
  2882     NPN_InvalidateRect(instanceData->npp, &r);
  2885   if (instanceData->slowPaint) {
  2886     XPSleep(1);
  2889   if (instanceData->runScriptOnPaint) {
  2890     NPObject* o = nullptr;
  2891     NPN_GetValue(instanceData->npp, NPNVPluginElementNPObject, &o);
  2892     if (o) {
  2893       NPVariant param;
  2894       STRINGZ_TO_NPVARIANT("paintscript", param);
  2895       NPVariant result;
  2896       NPN_Invoke(instanceData->npp, o, NPN_GetStringIdentifier("getAttribute"),
  2897                  &param, 1, &result);
  2899       if (NPVARIANT_IS_STRING(result)) {
  2900         NPObject* windowObject;
  2901         NPN_GetValue(instanceData->npp, NPNVWindowNPObject, &windowObject);
  2902         if (windowObject) {
  2903           NPVariant evalResult;
  2904           NPN_Evaluate(instanceData->npp, windowObject,
  2905                        (NPString*)&NPVARIANT_TO_STRING(result), &evalResult);
  2906           NPN_ReleaseVariantValue(&evalResult);
  2907           NPN_ReleaseObject(windowObject);
  2911       NPN_ReleaseVariantValue(&result);
  2912       NPN_ReleaseObject(o);
  2917 static const NPClass kTestSharedNPClass = {
  2918   NP_CLASS_STRUCT_VERSION,
  2919   // Everything else is nullptr
  2920 };
  2922 static bool getJavaCodebase(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2924   if (argCount != 0) {
  2925     return false;
  2928   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  2929   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  2931   char *outval = NPN_StrDup(id->javaCodebase.c_str());
  2932   STRINGZ_TO_NPVARIANT(outval, *result);
  2933   return true;
  2936 static bool getObjectValue(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2938   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  2940   NPObject* o = NPN_CreateObject(npp,
  2941                                  const_cast<NPClass*>(&kTestSharedNPClass));
  2942   if (!o)
  2943     return false;
  2945   OBJECT_TO_NPVARIANT(o, *result);
  2946   return true;
  2949 static bool checkObjectValue(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2951   VOID_TO_NPVARIANT(*result);
  2953   if (1 != argCount)
  2954     return false;
  2956   if (!NPVARIANT_IS_OBJECT(args[0]))
  2957     return false;
  2959   NPObject* o = NPVARIANT_TO_OBJECT(args[0]);
  2961   BOOLEAN_TO_NPVARIANT(o->_class == &kTestSharedNPClass, *result);
  2962   return true;
  2965 static bool enableFPExceptions(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  2967   VOID_TO_NPVARIANT(*result);
  2969 #if defined(XP_WIN) && defined(_M_IX86)
  2970   _control87(0, _MCW_EM);
  2971   return true;
  2972 #else
  2973   return false;
  2974 #endif
  2977 // caller is responsible for freeing return buffer
  2978 static char* URLForInstanceWindow(NPP instance) {
  2979   char *outString = nullptr;
  2981   NPObject* windowObject = nullptr;
  2982   NPError err = NPN_GetValue(instance, NPNVWindowNPObject, &windowObject);
  2983   if (err != NPERR_NO_ERROR || !windowObject)
  2984     return nullptr;
  2986   NPIdentifier locationIdentifier = NPN_GetStringIdentifier("location");
  2987   NPVariant locationVariant;
  2988   if (NPN_GetProperty(instance, windowObject, locationIdentifier, &locationVariant)) {
  2989     NPObject *locationObject = locationVariant.value.objectValue;
  2990     if (locationObject) {
  2991       NPIdentifier hrefIdentifier = NPN_GetStringIdentifier("href");
  2992       NPVariant hrefVariant;
  2993       if (NPN_GetProperty(instance, locationObject, hrefIdentifier, &hrefVariant)) {
  2994         const NPString* hrefString = &NPVARIANT_TO_STRING(hrefVariant);
  2995         if (hrefString) {
  2996           outString = (char *)malloc(hrefString->UTF8Length + 1);
  2997           if (outString) {
  2998             strcpy(outString, hrefString->UTF8Characters);
  2999             outString[hrefString->UTF8Length] = '\0';
  3002         NPN_ReleaseVariantValue(&hrefVariant);
  3005     NPN_ReleaseVariantValue(&locationVariant);
  3008   NPN_ReleaseObject(windowObject);
  3010   return outString;
  3013 static bool
  3014 setCookie(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  3016   if (argCount != 1)
  3017     return false;
  3018   if (!NPVARIANT_IS_STRING(args[0]))
  3019     return false;
  3020   const NPString* cookie = &NPVARIANT_TO_STRING(args[0]);
  3022   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  3024   char* url = URLForInstanceWindow(npp);
  3025   if (!url)
  3026     return false;
  3027   NPError err = NPN_SetValueForURL(npp, NPNURLVCookie, url, cookie->UTF8Characters, cookie->UTF8Length);
  3028   free(url);
  3030   return (err == NPERR_NO_ERROR);
  3033 static bool
  3034 getCookie(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  3036   if (argCount != 0)
  3037     return false;
  3039   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  3041   char* url = URLForInstanceWindow(npp);
  3042   if (!url)
  3043     return false;
  3044   char* cookie = nullptr;
  3045   unsigned int length = 0;
  3046   NPError err = NPN_GetValueForURL(npp, NPNURLVCookie, url, &cookie, &length);
  3047   free(url);
  3048   if (err != NPERR_NO_ERROR || !cookie)
  3049     return false;
  3051   STRINGZ_TO_NPVARIANT(cookie, *result);
  3052   return true;
  3055 static bool
  3056 getAuthInfo(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  3058   if (argCount != 5)
  3059     return false;
  3061   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  3063   if (!NPVARIANT_IS_STRING(args[0]) || !NPVARIANT_IS_STRING(args[1]) ||
  3064       !NPVARIANT_IS_INT32(args[2]) || !NPVARIANT_IS_STRING(args[3]) ||
  3065       !NPVARIANT_IS_STRING(args[4]))
  3066     return false;
  3068   const NPString* protocol = &NPVARIANT_TO_STRING(args[0]);
  3069   const NPString* host = &NPVARIANT_TO_STRING(args[1]);
  3070   uint32_t port = NPVARIANT_TO_INT32(args[2]);
  3071   const NPString* scheme = &NPVARIANT_TO_STRING(args[3]);
  3072   const NPString* realm = &NPVARIANT_TO_STRING(args[4]);
  3074   char* username = nullptr;
  3075   char* password = nullptr;
  3076   uint32_t ulen = 0, plen = 0;
  3078   NPError err = NPN_GetAuthenticationInfo(npp,
  3079       protocol->UTF8Characters,
  3080       host->UTF8Characters,
  3081       port,
  3082       scheme->UTF8Characters,
  3083       realm->UTF8Characters,
  3084       &username,
  3085       &ulen,
  3086       &password,
  3087       &plen);
  3089   if (err != NPERR_NO_ERROR) {
  3090     return false;
  3093   char* outstring = (char*)NPN_MemAlloc(ulen + plen + 2);
  3094   memset(outstring, 0, ulen + plen + 2);
  3095   strncpy(outstring, username, ulen);
  3096   strcat(outstring, "|");
  3097   strncat(outstring, password, plen);
  3099   STRINGZ_TO_NPVARIANT(outstring, *result);
  3101   NPN_MemFree(username);
  3102   NPN_MemFree(password);
  3104   return true;
  3107 static void timerCallback(NPP npp, uint32_t timerID)
  3109   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  3110   currentTimerEventCount++;
  3111   timerEvent event = timerEvents[currentTimerEventCount];
  3113   NPObject* windowObject;
  3114   NPN_GetValue(npp, NPNVWindowNPObject, &windowObject);
  3115   if (!windowObject)
  3116     return;
  3118   NPVariant rval;
  3119   if (timerID != id->timerID[event.timerIdReceive]) {
  3120     id->timerTestResult = false;
  3123   if (currentTimerEventCount == totalTimerEvents - 1) {
  3124     NPVariant arg;
  3125     BOOLEAN_TO_NPVARIANT(id->timerTestResult, arg);
  3126     NPN_Invoke(npp, windowObject, NPN_GetStringIdentifier(id->timerTestScriptCallback.c_str()), &arg, 1, &rval);
  3127     NPN_ReleaseVariantValue(&arg);
  3130   NPN_ReleaseObject(windowObject);
  3132   if (event.timerIdSchedule > -1) {
  3133     id->timerID[event.timerIdSchedule] = NPN_ScheduleTimer(npp, event.timerInterval, event.timerRepeat, timerCallback);
  3135   if (event.timerIdUnschedule > -1) {
  3136     NPN_UnscheduleTimer(npp, id->timerID[event.timerIdUnschedule]);
  3140 static bool
  3141 timerTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  3143   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  3144   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  3145   currentTimerEventCount = 0;
  3147   if (argCount < 1 || !NPVARIANT_IS_STRING(args[0]))
  3148     return false;
  3149   const NPString* argstr = &NPVARIANT_TO_STRING(args[0]);
  3150   id->timerTestScriptCallback = argstr->UTF8Characters;
  3152   id->timerTestResult = true;
  3153   timerEvent event = timerEvents[currentTimerEventCount];
  3155   id->timerID[event.timerIdSchedule] = NPN_ScheduleTimer(npp, event.timerInterval, event.timerRepeat, timerCallback);
  3157   return id->timerID[event.timerIdSchedule] != 0;
  3160 #ifdef XP_WIN
  3161 void
  3162 ThreadProc(void* cookie)
  3163 #else
  3164 void*
  3165 ThreadProc(void* cookie)
  3166 #endif
  3168   NPObject* npobj = (NPObject*)cookie;
  3169   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  3170   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  3171   id->asyncTestPhase = 1;
  3172   NPN_PluginThreadAsyncCall(npp, asyncCallback, (void*)npobj);
  3173 #ifndef XP_WIN
  3174   return nullptr;
  3175 #endif
  3178 void
  3179 asyncCallback(void* cookie)
  3181   NPObject* npobj = (NPObject*)cookie;
  3182   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  3183   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  3185   switch (id->asyncTestPhase) {
  3186     // async callback triggered from same thread
  3187     case 0:
  3188 #ifdef XP_WIN
  3189       if (_beginthread(ThreadProc, 0, (void*)npobj) == -1)
  3190         id->asyncCallbackResult = false;
  3191 #else
  3192       pthread_t tid;
  3193       if (pthread_create(&tid, 0, ThreadProc, (void*)npobj))
  3194         id->asyncCallbackResult = false;
  3195 #endif
  3196       break;
  3198     // async callback triggered from different thread
  3199     default:
  3200       NPObject* windowObject;
  3201       NPN_GetValue(npp, NPNVWindowNPObject, &windowObject);
  3202       if (!windowObject)
  3203         return;
  3204       NPVariant arg, rval;
  3205       BOOLEAN_TO_NPVARIANT(id->asyncCallbackResult, arg);
  3206       NPN_Invoke(npp, windowObject, NPN_GetStringIdentifier(id->asyncTestScriptCallback.c_str()), &arg, 1, &rval);
  3207       NPN_ReleaseVariantValue(&arg);
  3208       NPN_ReleaseObject(windowObject);
  3209       break;
  3213 static bool
  3214 asyncCallbackTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  3216   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  3217   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  3219   if (argCount < 1 || !NPVARIANT_IS_STRING(args[0]))
  3220     return false;
  3221   const NPString* argstr = &NPVARIANT_TO_STRING(args[0]);
  3222   id->asyncTestScriptCallback = argstr->UTF8Characters;
  3224   id->asyncTestPhase = 0;
  3225   id->asyncCallbackResult = true;
  3226   NPN_PluginThreadAsyncCall(npp, asyncCallback, (void*)npobj);
  3228   return true;
  3231 static bool
  3232 GCRaceInvoke(NPObject*, NPIdentifier, const NPVariant*, uint32_t, NPVariant*)
  3234   return false;
  3237 static bool
  3238 GCRaceInvokeDefault(NPObject* o, const NPVariant* args, uint32_t argCount,
  3239 		    NPVariant* result)
  3241   if (1 != argCount || !NPVARIANT_IS_INT32(args[0]) ||
  3242       35 != NPVARIANT_TO_INT32(args[0]))
  3243     return false;
  3245   return true;
  3248 static const NPClass kGCRaceClass = {
  3249   NP_CLASS_STRUCT_VERSION,
  3250   nullptr,
  3251   nullptr,
  3252   nullptr,
  3253   nullptr,
  3254   GCRaceInvoke,
  3255   GCRaceInvokeDefault,
  3256   nullptr,
  3257   nullptr,
  3258   nullptr,
  3259   nullptr,
  3260   nullptr,
  3261   nullptr
  3262 };
  3264 struct GCRaceData
  3266   GCRaceData(NPP npp, NPObject* callback, NPObject* localFunc)
  3267     : npp_(npp)
  3268     , callback_(callback)
  3269     , localFunc_(localFunc)
  3271     NPN_RetainObject(callback_);
  3272     NPN_RetainObject(localFunc_);
  3275   ~GCRaceData()
  3277     NPN_ReleaseObject(callback_);
  3278     NPN_ReleaseObject(localFunc_);
  3281   NPP npp_;
  3282   NPObject* callback_;
  3283   NPObject* localFunc_;
  3284 };
  3286 static void
  3287 FinishGCRace(void* closure)
  3289   GCRaceData* rd = static_cast<GCRaceData*>(closure);
  3291   XPSleep(5);
  3293   NPVariant arg;
  3294   OBJECT_TO_NPVARIANT(rd->localFunc_, arg);
  3296   NPVariant result;
  3297   bool ok = NPN_InvokeDefault(rd->npp_, rd->callback_, &arg, 1, &result);
  3298   if (!ok)
  3299     return;
  3301   NPN_ReleaseVariantValue(&result);
  3302   delete rd;
  3305 bool
  3306 checkGCRace(NPObject* npobj, const NPVariant* args, uint32_t argCount,
  3307 	    NPVariant* result)
  3309   if (1 != argCount || !NPVARIANT_IS_OBJECT(args[0]))
  3310     return false;
  3312   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  3314   NPObject* localFunc =
  3315     NPN_CreateObject(npp, const_cast<NPClass*>(&kGCRaceClass));
  3317   GCRaceData* rd =
  3318     new GCRaceData(npp, NPVARIANT_TO_OBJECT(args[0]), localFunc);
  3319   NPN_PluginThreadAsyncCall(npp, FinishGCRace, rd);
  3321   OBJECT_TO_NPVARIANT(localFunc, *result);
  3322   return true;
  3325 bool
  3326 hangPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount,
  3327            NPVariant* result)
  3329   mozilla::NoteIntentionalCrash("plugin");
  3331   bool busyHang = false;
  3332   if ((argCount == 1) && NPVARIANT_IS_BOOLEAN(args[0])) {
  3333     busyHang = NPVARIANT_TO_BOOLEAN(args[0]);
  3336   if (busyHang) {
  3337     const time_t start = std::time(nullptr);
  3338     while ((std::time(nullptr) - start) < 100000) {
  3339       volatile int dummy = 0;
  3340       for (int i=0; i<1000; ++i) {
  3341         dummy++;
  3344   } else {
  3345 #ifdef XP_WIN
  3346   Sleep(100000000);
  3347     Sleep(100000000);
  3348 #else
  3349   pause();
  3350     pause();
  3351 #endif
  3354   // NB: returning true here means that we weren't terminated, and
  3355   // thus the hang detection/handling didn't work correctly.  The
  3356   // test harness will succeed in calling this function, and the
  3357   // test will fail.
  3358   return true;
  3361 bool
  3362 stallPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount,
  3363            NPVariant* result)
  3365   uint32_t stallTimeSeconds = 0;
  3366   if ((argCount == 1) && NPVARIANT_IS_INT32(args[0])) {
  3367     stallTimeSeconds = (uint32_t) NPVARIANT_TO_INT32(args[0]);
  3370 #ifdef XP_WIN
  3371   Sleep(stallTimeSeconds * 1000U);
  3372 #else
  3373   sleep(stallTimeSeconds);
  3374 #endif
  3376   return true;
  3379 #if defined(MOZ_WIDGET_GTK)
  3380 bool
  3381 getClipboardText(NPObject* npobj, const NPVariant* args, uint32_t argCount,
  3382                  NPVariant* result)
  3384   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  3385   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  3386   string sel = pluginGetClipboardText(id);
  3388   uint32_t len = sel.size();
  3389   char* selCopy = static_cast<char*>(NPN_MemAlloc(1 + len));
  3390   if (!selCopy)
  3391     return false;
  3393   memcpy(selCopy, sel.c_str(), len);
  3394   selCopy[len] = '\0';
  3396   STRINGN_TO_NPVARIANT(selCopy, len, *result);
  3397   // *result owns str now
  3399   return true;
  3402 bool
  3403 crashPluginInNestedLoop(NPObject* npobj, const NPVariant* args,
  3404                         uint32_t argCount, NPVariant* result)
  3406   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  3407   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  3408   return pluginCrashInNestedLoop(id);
  3411 bool
  3412 destroySharedGfxStuff(NPObject* npobj, const NPVariant* args,
  3413                         uint32_t argCount, NPVariant* result)
  3415   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  3416   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  3417   return pluginDestroySharedGfxStuff(id);
  3420 #else
  3421 bool
  3422 getClipboardText(NPObject* npobj, const NPVariant* args, uint32_t argCount,
  3423                  NPVariant* result)
  3425   // XXX Not implemented!
  3426   return false;
  3429 bool
  3430 crashPluginInNestedLoop(NPObject* npobj, const NPVariant* args,
  3431                         uint32_t argCount, NPVariant* result)
  3433   // XXX Not implemented!
  3434   return false;
  3437 bool
  3438 destroySharedGfxStuff(NPObject* npobj, const NPVariant* args,
  3439                         uint32_t argCount, NPVariant* result)
  3441   // XXX Not implemented!
  3442   return false;
  3444 #endif
  3446 bool
  3447 callOnDestroy(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  3449   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  3450   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  3452   if (id->callOnDestroy)
  3453     return false;
  3455   if (1 != argCount || !NPVARIANT_IS_OBJECT(args[0]))
  3456     return false;
  3458   id->callOnDestroy = NPVARIANT_TO_OBJECT(args[0]);
  3459   NPN_RetainObject(id->callOnDestroy);
  3461   return true;
  3464 // On Linux at least, a windowed plugin resize causes Flash Player to
  3465 // reconnect to the browser window.  This method simulates that.
  3466 bool
  3467 reinitWidget(NPObject* npobj, const NPVariant* args, uint32_t argCount,
  3468              NPVariant* result)
  3470   if (argCount != 0)
  3471     return false;
  3473   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  3474   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  3476   if (!id->hasWidget)
  3477     return false;
  3479   pluginWidgetInit(id, id->window.window);
  3480   return true;
  3483 bool
  3484 propertyAndMethod(NPObject* npobj, const NPVariant* args, uint32_t argCount,
  3485                   NPVariant* result)
  3487   INT32_TO_NPVARIANT(5, *result);
  3488   return true;
  3491 // Returns top-level window activation state as indicated by Cocoa NPAPI's
  3492 // NPCocoaEventWindowFocusChanged events - 'true' if active, 'false' if not.
  3493 // Throws an exception if no events have been received and thus this state
  3494 // is unknown.
  3495 bool
  3496 getTopLevelWindowActivationState(NPObject* npobj, const NPVariant* args, uint32_t argCount,
  3497                                  NPVariant* result)
  3499   if (argCount != 0)
  3500     return false;
  3502   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  3503   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  3505   // Throw an exception for unknown state.
  3506   if (id->topLevelWindowActivationState == ACTIVATION_STATE_UNKNOWN) {
  3507     return false;
  3510   if (id->topLevelWindowActivationState == ACTIVATION_STATE_ACTIVATED) {
  3511     BOOLEAN_TO_NPVARIANT(true, *result);
  3512   } else if (id->topLevelWindowActivationState == ACTIVATION_STATE_DEACTIVATED) {
  3513     BOOLEAN_TO_NPVARIANT(false, *result);
  3516   return true;
  3519 bool
  3520 getTopLevelWindowActivationEventCount(NPObject* npobj, const NPVariant* args, uint32_t argCount,
  3521                                       NPVariant* result)
  3523   if (argCount != 0)
  3524     return false;
  3526   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  3527   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  3529   INT32_TO_NPVARIANT(id->topLevelWindowActivationEventCount, *result);
  3531   return true;
  3534 // Returns top-level window activation state as indicated by Cocoa NPAPI's
  3535 // NPCocoaEventWindowFocusChanged events - 'true' if active, 'false' if not.
  3536 // Throws an exception if no events have been received and thus this state
  3537 // is unknown.
  3538 bool
  3539 getFocusState(NPObject* npobj, const NPVariant* args, uint32_t argCount,
  3540               NPVariant* result)
  3542   if (argCount != 0)
  3543     return false;
  3545   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  3546   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  3548   // Throw an exception for unknown state.
  3549   if (id->focusState == ACTIVATION_STATE_UNKNOWN) {
  3550     return false;
  3553   if (id->focusState == ACTIVATION_STATE_ACTIVATED) {
  3554     BOOLEAN_TO_NPVARIANT(true, *result);
  3555   } else if (id->focusState == ACTIVATION_STATE_DEACTIVATED) {
  3556     BOOLEAN_TO_NPVARIANT(false, *result);
  3559   return true;
  3562 bool
  3563 getFocusEventCount(NPObject* npobj, const NPVariant* args, uint32_t argCount,
  3564                    NPVariant* result)
  3566   if (argCount != 0)
  3567     return false;
  3569   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  3570   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  3572   INT32_TO_NPVARIANT(id->focusEventCount, *result);
  3574   return true;
  3577 bool
  3578 getEventModel(NPObject* npobj, const NPVariant* args, uint32_t argCount,
  3579               NPVariant* result)
  3581   if (argCount != 0)
  3582     return false;
  3584   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  3585   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  3587   INT32_TO_NPVARIANT(id->eventModel, *result);
  3589   return true;
  3592 static bool
  3593 ReflectorHasMethod(NPObject* npobj, NPIdentifier name)
  3595   return false;
  3598 static bool
  3599 ReflectorHasProperty(NPObject* npobj, NPIdentifier name)
  3601   return true;
  3604 static bool
  3605 ReflectorGetProperty(NPObject* npobj, NPIdentifier name, NPVariant* result)
  3607   if (NPN_IdentifierIsString(name)) {
  3608     char* s = NPN_UTF8FromIdentifier(name);
  3609     STRINGZ_TO_NPVARIANT(s, *result);
  3610     return true;
  3613   INT32_TO_NPVARIANT(NPN_IntFromIdentifier(name), *result);
  3614   return true;
  3617 static const NPClass kReflectorNPClass = {
  3618   NP_CLASS_STRUCT_VERSION,
  3619   nullptr,
  3620   nullptr,
  3621   nullptr,
  3622   ReflectorHasMethod,
  3623   nullptr,
  3624   nullptr,
  3625   ReflectorHasProperty,
  3626   ReflectorGetProperty,
  3627   nullptr,
  3628   nullptr,
  3629   nullptr,
  3630   nullptr
  3631 };
  3633 bool
  3634 getReflector(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  3636   if (0 != argCount)
  3637     return false;
  3639   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  3641   NPObject* reflector =
  3642     NPN_CreateObject(npp,
  3643 		     const_cast<NPClass*>(&kReflectorNPClass)); // retains
  3644   OBJECT_TO_NPVARIANT(reflector, *result);
  3645   return true;
  3648 bool isVisible(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  3650   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  3651   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  3653   BOOLEAN_TO_NPVARIANT(id->window.clipRect.top != 0 ||
  3654 		       id->window.clipRect.left != 0 ||
  3655 		       id->window.clipRect.bottom != 0 ||
  3656 		       id->window.clipRect.right != 0, *result);
  3657   return true;
  3660 bool getWindowPosition(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  3662   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  3663   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  3665   NPObject* window = nullptr;
  3666   NPError err = NPN_GetValue(npp, NPNVWindowNPObject, &window);
  3667   if (NPERR_NO_ERROR != err || !window)
  3668     return false;
  3670   NPIdentifier arrayID = NPN_GetStringIdentifier("Array");
  3671   NPVariant arrayFunctionV;
  3672   bool ok = NPN_GetProperty(npp, window, arrayID, &arrayFunctionV);
  3674   NPN_ReleaseObject(window);
  3676   if (!ok)
  3677     return false;
  3679   if (!NPVARIANT_IS_OBJECT(arrayFunctionV)) {
  3680     NPN_ReleaseVariantValue(&arrayFunctionV);
  3681     return false;
  3683   NPObject* arrayFunction = NPVARIANT_TO_OBJECT(arrayFunctionV);
  3685   NPVariant elements[4];
  3686   INT32_TO_NPVARIANT(id->window.x, elements[0]);
  3687   INT32_TO_NPVARIANT(id->window.y, elements[1]);
  3688   INT32_TO_NPVARIANT(id->window.width, elements[2]);
  3689   INT32_TO_NPVARIANT(id->window.height, elements[3]);
  3691   ok = NPN_InvokeDefault(npp, arrayFunction, elements, 4, result);
  3693   NPN_ReleaseObject(arrayFunction);
  3695   return ok;
  3698 bool constructObject(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  3700   if (argCount == 0 || !NPVARIANT_IS_OBJECT(args[0]))
  3701     return false;
  3703   NPObject* ctor = NPVARIANT_TO_OBJECT(args[0]);
  3705   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  3707   return NPN_Construct(npp, ctor, args + 1, argCount - 1, result);
  3710 bool setSitesWithData(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  3712   if (argCount != 1 || !NPVARIANT_IS_STRING(args[0]))
  3713     return false;
  3715   // Clear existing data.
  3716   delete sSitesWithData;
  3718   const NPString* str = &NPVARIANT_TO_STRING(args[0]);
  3719   if (str->UTF8Length == 0)
  3720     return true;
  3722   // Parse the comma-delimited string into a vector.
  3723   sSitesWithData = new list<siteData>;
  3724   const char* iterator = str->UTF8Characters;
  3725   const char* end = iterator + str->UTF8Length;
  3726   while (1) {
  3727     const char* next = strchr(iterator, ',');
  3728     if (!next)
  3729       next = end;
  3731     // Parse out the three tokens into a siteData struct.
  3732     const char* siteEnd = strchr(iterator, ':');
  3733     *((char*) siteEnd) = '\0';
  3734     const char* flagsEnd = strchr(siteEnd + 1, ':');
  3735     *((char*) flagsEnd) = '\0';
  3736     *((char*) next) = '\0';
  3738     siteData data;
  3739     data.site = string(iterator);
  3740     data.flags = atoi(siteEnd + 1);
  3741     data.age = atoi(flagsEnd + 1);
  3743     sSitesWithData->push_back(data);
  3745     if (next == end)
  3746       break;
  3748     iterator = next + 1;
  3751   return true;
  3754 bool setSitesWithDataCapabilities(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  3756   if (argCount != 1 || !NPVARIANT_IS_BOOLEAN(args[0]))
  3757     return false;
  3759   sClearByAgeSupported = NPVARIANT_TO_BOOLEAN(args[0]);
  3760   return true;
  3763 bool getLastKeyText(NPObject* npobj, const NPVariant* args, uint32_t argCount,
  3764                     NPVariant* result)
  3766   if (argCount != 0) {
  3767     return false;
  3770   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  3771   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  3773   char *outval = NPN_StrDup(id->lastKeyText.c_str());
  3774   STRINGZ_TO_NPVARIANT(outval, *result);
  3775   return true;
  3778 bool getNPNVdocumentOrigin(NPObject* npobj, const NPVariant* args, uint32_t argCount,
  3779                            NPVariant* result)
  3781   if (argCount != 0) {
  3782     return false;
  3785   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  3787   char *origin = nullptr;
  3788   NPError err = NPN_GetValue(npp, NPNVdocumentOrigin, &origin);
  3789   if (err != NPERR_NO_ERROR) {
  3790     return false;
  3793   STRINGZ_TO_NPVARIANT(origin, *result);
  3794   return true;
  3797 bool getMouseUpEventCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  3799   if (argCount != 0) {
  3800     return false;
  3803   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
  3804   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
  3805   INT32_TO_NPVARIANT(id->mouseUpEventCount, *result);
  3806   return true;
  3809 bool queryContentsScaleFactor(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
  3811   if (argCount != 0)
  3812     return false;
  3814   double scaleFactor = 1.0;
  3815 #if defined(XP_MACOSX)
  3816   NPError err = NPN_GetValue(static_cast<TestNPObject*>(npobj)->npp,
  3817                              NPNVcontentsScaleFactor, &scaleFactor);
  3818   if (err != NPERR_NO_ERROR) {
  3819     return false;
  3821 #endif
  3822   DOUBLE_TO_NPVARIANT(scaleFactor, *result);
  3823   return true;

mercurial