Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
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;
1006 }
1007 }
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;
1016 }
1017 }
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;
1031 }
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;
1046 }
1047 }
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;
1056 }
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;
1064 }
1065 }
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;
1071 }
1072 }
1074 if ((instanceData->bugMode == 813906) && instanceData->frame.length()) {
1075 bug813906(instance, "f", "browser.xul", instanceData->frame.c_str());
1076 }
1078 return NPERR_NO_ERROR;
1079 }
1081 NPError
1082 NPP_Destroy(NPP instance, NPSavedData** save)
1083 {
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);
1095 }
1097 if (instanceData->streamBuf) {
1098 free(instanceData->streamBuf);
1099 }
1100 if (instanceData->fileBuf) {
1101 free(instanceData->fileBuf);
1102 }
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;
1110 }
1112 if (instanceData->frontBuffer) {
1113 NPN_SetCurrentAsyncSurface(instance, nullptr, nullptr);
1114 NPN_FinalizeAsyncSurface(instance, instanceData->frontBuffer);
1115 NPN_MemFree(instanceData->frontBuffer);
1116 }
1117 if (instanceData->backBuffer) {
1118 NPN_FinalizeAsyncSurface(instance, instanceData->backBuffer);
1119 NPN_MemFree(instanceData->backBuffer);
1120 }
1122 pluginInstanceShutdown(instanceData);
1123 NPN_ReleaseObject(instanceData->scriptableObject);
1125 if (sCurrentInstanceCountWatchGeneration == instanceData->instanceCountWatchGeneration) {
1126 --sInstanceCount;
1127 }
1128 delete instanceData;
1130 return NPERR_NO_ERROR;
1131 }
1133 NPError
1134 NPP_SetWindow(NPP instance, NPWindow* window)
1135 {
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);
1146 }
1148 void* oldWindow = instanceData->window.window;
1149 pluginDoSetWindow(instanceData, window);
1150 if (instanceData->hasWidget && oldWindow != instanceData->window.window) {
1151 pluginWidgetInit(instanceData, oldWindow);
1152 }
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;
1161 }
1162 if (instanceData->frontBuffer) {
1163 NPN_FinalizeAsyncSurface(instance, instanceData->frontBuffer);
1164 NPN_MemFree(instanceData->frontBuffer);
1165 }
1166 if (instanceData->backBuffer) {
1167 NPN_FinalizeAsyncSurface(instance, instanceData->backBuffer);
1168 NPN_MemFree(instanceData->backBuffer);
1169 }
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);
1183 }
1184 return NPERR_NO_ERROR;
1185 }
1187 NPError
1188 NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype)
1189 {
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);
1198 }
1199 return instanceData->failureCode;
1200 }
1202 if (stream->notifyData &&
1203 static_cast<URLNotifyData*>(stream->notifyData) != &kNotifyData) {
1204 // stream from streamTest
1205 *stype = NP_NORMAL;
1206 }
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;
1216 }
1217 else {
1218 // We already got a stream and didn't ask for another one.
1219 instanceData->err << "Received unexpected multiple NPP_NewStream";
1220 }
1221 }
1222 }
1223 return NPERR_NO_ERROR;
1224 }
1226 NPError
1227 NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason)
1228 {
1229 printf("NPP_DestroyStream\n");
1230 InstanceData* instanceData = (InstanceData*)(instance->pdata);
1232 if (instanceData->functionToFail == FUNCTION_NPP_NEWSTREAM) {
1233 instanceData->err << "NPP_DestroyStream called";
1234 }
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";
1241 }
1243 if (instanceData->functionToFail == FUNCTION_NPP_DESTROYSTREAM &&
1244 instanceData->failureCode) {
1245 instanceData->err << SUCCESS_STRING;
1246 if (instanceData->frame.length() > 0) {
1247 sendBufferToFrame(instance);
1248 }
1249 return instanceData->failureCode;
1250 }
1252 URLNotifyData* nd = static_cast<URLNotifyData*>(stream->notifyData);
1253 if (nd && nd != &kNotifyData) {
1254 return NPERR_NO_ERROR;
1255 }
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;
1263 }
1265 if (!instanceData->fileBuf) {
1266 instanceData->err <<
1267 "Error: no data written with NPP_StreamAsFile";
1268 return NPERR_GENERIC_ERROR;
1269 }
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";
1275 }
1276 }
1277 if (instanceData->frame.length() > 0 &&
1278 instanceData->testFunction != FUNCTION_NPP_GETURLNOTIFY &&
1279 instanceData->testFunction != FUNCTION_NPP_POSTURL) {
1280 sendBufferToFrame(instance);
1281 }
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;
1289 }
1290 return NPERR_NO_ERROR;
1291 }
1293 int32_t
1294 NPP_WriteReady(NPP instance, NPStream* stream)
1295 {
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";
1301 }
1303 // temporarily disabled per bug 519870
1304 //if (instanceData->writeReadyCount == 1) {
1305 // return 0;
1306 //}
1308 return instanceData->streamChunkSize;
1309 }
1311 int32_t
1312 NPP_Write(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer)
1313 {
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;
1331 }
1333 if (instanceData->functionToFail == FUNCTION_NPP_NEWSTREAM) {
1334 instanceData->err << "NPP_Write called";
1335 }
1337 if (instanceData->functionToFail == FUNCTION_NPP_WRITE) {
1338 return -1;
1339 }
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);
1350 }
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;
1358 }
1360 if (instanceData->closeStream) {
1361 instanceData->closeStream = false;
1362 if (instanceData->testrange != nullptr) {
1363 NPN_RequestRead(stream, instanceData->testrange);
1364 }
1365 NPN_DestroyStream(instance, stream, NPRES_USER_BREAK);
1366 }
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;
1379 }
1380 printf("called NPN_RequestRead, return %d\n", err);
1381 }
1382 }
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";
1389 }
1390 else {
1391 printf("data matches!\n");
1392 }
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;
1399 }
1400 if (range->waiting) stillwaiting = true;
1401 range = reinterpret_cast<TestRange*>(range->next);
1402 }
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;
1407 }
1408 }
1409 }
1410 else {
1411 if (instanceData->streamBufSize == 0) {
1412 instanceData->streamBuf = malloc(len + 1);
1413 streamBuf = reinterpret_cast<char *>(instanceData->streamBuf);
1414 }
1415 else {
1416 instanceData->streamBuf =
1417 realloc(reinterpret_cast<char *>(instanceData->streamBuf),
1418 instanceData->streamBufSize + len + 1);
1419 streamBuf = reinterpret_cast<char *>(instanceData->streamBuf);
1420 }
1421 memcpy(streamBuf + instanceData->streamBufSize, buffer, len);
1422 instanceData->streamBufSize = instanceData->streamBufSize + len;
1423 streamBuf[instanceData->streamBufSize] = '\0';
1424 }
1425 return len;
1426 }
1428 void
1429 NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname)
1430 {
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";
1439 }
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;
1455 }
1456 fclose(file);
1457 buf[size] = '\0';
1458 instanceData->fileBufSize = (int32_t)size;
1459 }
1460 else {
1461 printf("Unable to open file\n");
1462 instanceData->err << "Unable to open file " << fname;
1463 }
1464 }
1466 void
1467 NPP_Print(NPP instance, NPPrint* platformPrint)
1468 {
1469 }
1471 int16_t
1472 NPP_HandleEvent(NPP instance, void* event)
1473 {
1474 InstanceData* instanceData = (InstanceData*)(instance->pdata);
1475 return pluginHandleEvent(instanceData, event);
1476 }
1478 void
1479 NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData)
1480 {
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);
1488 }
1489 }
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]);
1496 }
1497 else {
1498 STRINGN_TO_NPVARIANT("", 0, args[1]);
1499 }
1501 NPVariant result;
1502 NPN_InvokeDefault(instance, ndata->notifyCallback, args, 2, &result);
1503 NPN_ReleaseVariantValue(&result);
1504 }
1506 // clean up the URLNotifyData
1507 if (ndata->writeCallback) {
1508 NPN_ReleaseObject(ndata->writeCallback);
1509 }
1510 if (ndata->notifyCallback) {
1511 NPN_ReleaseObject(ndata->notifyCallback);
1512 }
1513 if (ndata->redirectCallback) {
1514 NPN_ReleaseObject(ndata->redirectCallback);
1515 }
1516 free(ndata->data);
1517 delete ndata;
1518 }
1519 else {
1520 printf("ERROR! NPP_URLNotify called with wrong cookie\n");
1521 instanceData->err << "Error: NPP_URLNotify called with wrong cookie";
1522 }
1523 }
1525 NPError
1526 NPP_GetValue(NPP instance, NPPVariable variable, void* value)
1527 {
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;
1534 }
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;
1540 }
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;
1545 }
1547 return NPERR_GENERIC_ERROR;
1548 }
1550 NPError
1551 NPP_SetValue(NPP instance, NPNVariable variable, void* value)
1552 {
1553 if (variable == NPNVprivateModeBool) {
1554 InstanceData* instanceData = (InstanceData*)(instance->pdata);
1555 instanceData->lastReportedPrivateModeState = bool(*static_cast<NPBool*>(value));
1556 return NPERR_NO_ERROR;
1557 }
1558 return NPERR_GENERIC_ERROR;
1559 }
1561 void
1562 NPP_URLRedirectNotify(NPP instance, const char* url, int32_t status, void* notifyData)
1563 {
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);
1574 }
1575 NPN_URLRedirectResponse(instance, notifyData, nd->allowRedirects);
1576 return;
1577 }
1578 NPN_URLRedirectResponse(instance, notifyData, true);
1579 }
1581 NPError
1582 NPP_ClearSiteData(const char* site, uint64_t flags, uint64_t maxAge)
1583 {
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);
1602 }
1603 iter = next;
1604 }
1606 return NPERR_NO_ERROR;
1607 }
1609 char**
1610 NPP_GetSitesWithData()
1611 {
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;
1626 }
1628 // Iterate the list of stored data, and build a list of strings.
1629 list<string> sites;
1630 {
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);
1636 }
1637 }
1639 // Remove duplicate strings.
1640 sites.sort();
1641 sites.unique();
1643 // Add strings to the result array, and null terminate.
1644 {
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);
1652 }
1653 }
1654 result[sites.size()] = nullptr;
1656 return result;
1657 }
1659 //
1660 // npapi browser functions
1661 //
1663 bool
1664 NPN_SetProperty(NPP instance, NPObject* obj, NPIdentifier propertyName, const NPVariant* value)
1665 {
1666 return sBrowserFuncs->setproperty(instance, obj, propertyName, value);
1667 }
1669 NPIdentifier
1670 NPN_GetIntIdentifier(int32_t intid)
1671 {
1672 return sBrowserFuncs->getintidentifier(intid);
1673 }
1675 NPIdentifier
1676 NPN_GetStringIdentifier(const NPUTF8* name)
1677 {
1678 return sBrowserFuncs->getstringidentifier(name);
1679 }
1681 void
1682 NPN_GetStringIdentifiers(const NPUTF8 **names, int32_t nameCount, NPIdentifier *identifiers)
1683 {
1684 return sBrowserFuncs->getstringidentifiers(names, nameCount, identifiers);
1685 }
1687 bool
1688 NPN_IdentifierIsString(NPIdentifier identifier)
1689 {
1690 return sBrowserFuncs->identifierisstring(identifier);
1691 }
1693 NPUTF8*
1694 NPN_UTF8FromIdentifier(NPIdentifier identifier)
1695 {
1696 return sBrowserFuncs->utf8fromidentifier(identifier);
1697 }
1699 int32_t
1700 NPN_IntFromIdentifier(NPIdentifier identifier)
1701 {
1702 return sBrowserFuncs->intfromidentifier(identifier);
1703 }
1705 NPError
1706 NPN_GetValue(NPP instance, NPNVariable variable, void* value)
1707 {
1708 return sBrowserFuncs->getvalue(instance, variable, value);
1709 }
1711 NPError
1712 NPN_SetValue(NPP instance, NPPVariable variable, void* value)
1713 {
1714 return sBrowserFuncs->setvalue(instance, variable, value);
1715 }
1717 void
1718 NPN_InvalidateRect(NPP instance, NPRect* rect)
1719 {
1720 sBrowserFuncs->invalidaterect(instance, rect);
1721 }
1723 bool
1724 NPN_HasProperty(NPP instance, NPObject* obj, NPIdentifier propertyName)
1725 {
1726 return sBrowserFuncs->hasproperty(instance, obj, propertyName);
1727 }
1729 NPObject*
1730 NPN_CreateObject(NPP instance, NPClass* aClass)
1731 {
1732 return sBrowserFuncs->createobject(instance, aClass);
1733 }
1735 bool
1736 NPN_Invoke(NPP npp, NPObject* obj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result)
1737 {
1738 return sBrowserFuncs->invoke(npp, obj, methodName, args, argCount, result);
1739 }
1741 bool
1742 NPN_InvokeDefault(NPP npp, NPObject* obj, const NPVariant *args, uint32_t argCount, NPVariant *result)
1743 {
1744 return sBrowserFuncs->invokeDefault(npp, obj, args, argCount, result);
1745 }
1747 bool
1748 NPN_Construct(NPP npp, NPObject* npobj, const NPVariant* args,
1749 uint32_t argCount, NPVariant* result)
1750 {
1751 return sBrowserFuncs->construct(npp, npobj, args, argCount, result);
1752 }
1754 const char*
1755 NPN_UserAgent(NPP instance)
1756 {
1757 return sBrowserFuncs->uagent(instance);
1758 }
1760 NPObject*
1761 NPN_RetainObject(NPObject* obj)
1762 {
1763 return sBrowserFuncs->retainobject(obj);
1764 }
1766 void
1767 NPN_ReleaseObject(NPObject* obj)
1768 {
1769 return sBrowserFuncs->releaseobject(obj);
1770 }
1772 void*
1773 NPN_MemAlloc(uint32_t size)
1774 {
1775 return sBrowserFuncs->memalloc(size);
1776 }
1778 char*
1779 NPN_StrDup(const char* str)
1780 {
1781 return strcpy((char*)sBrowserFuncs->memalloc(strlen(str) + 1), str);
1782 }
1784 void
1785 NPN_MemFree(void* ptr)
1786 {
1787 return sBrowserFuncs->memfree(ptr);
1788 }
1790 uint32_t
1791 NPN_ScheduleTimer(NPP instance, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID))
1792 {
1793 return sBrowserFuncs->scheduletimer(instance, interval, repeat, timerFunc);
1794 }
1796 void
1797 NPN_UnscheduleTimer(NPP instance, uint32_t timerID)
1798 {
1799 return sBrowserFuncs->unscheduletimer(instance, timerID);
1800 }
1802 void
1803 NPN_ReleaseVariantValue(NPVariant *variant)
1804 {
1805 return sBrowserFuncs->releasevariantvalue(variant);
1806 }
1808 NPError
1809 NPN_GetURLNotify(NPP instance, const char* url, const char* target, void* notifyData)
1810 {
1811 return sBrowserFuncs->geturlnotify(instance, url, target, notifyData);
1812 }
1814 NPError
1815 NPN_GetURL(NPP instance, const char* url, const char* target)
1816 {
1817 return sBrowserFuncs->geturl(instance, url, target);
1818 }
1820 NPError
1821 NPN_RequestRead(NPStream* stream, NPByteRange* rangeList)
1822 {
1823 return sBrowserFuncs->requestread(stream, rangeList);
1824 }
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)
1830 {
1831 return sBrowserFuncs->posturlnotify(instance, url, target, len, buf, file, notifyData);
1832 }
1834 NPError
1835 NPN_PostURL(NPP instance, const char *url,
1836 const char *target, uint32_t len,
1837 const char *buf, NPBool file)
1838 {
1839 return sBrowserFuncs->posturl(instance, url, target, len, buf, file);
1840 }
1842 NPError
1843 NPN_DestroyStream(NPP instance, NPStream* stream, NPError reason)
1844 {
1845 return sBrowserFuncs->destroystream(instance, stream, reason);
1846 }
1848 NPError
1849 NPN_NewStream(NPP instance,
1850 NPMIMEType type,
1851 const char* target,
1852 NPStream** stream)
1853 {
1854 return sBrowserFuncs->newstream(instance, type, target, stream);
1855 }
1857 int32_t
1858 NPN_Write(NPP instance,
1859 NPStream* stream,
1860 int32_t len,
1861 void* buf)
1862 {
1863 return sBrowserFuncs->write(instance, stream, len, buf);
1864 }
1866 bool
1867 NPN_Enumerate(NPP instance,
1868 NPObject *npobj,
1869 NPIdentifier **identifiers,
1870 uint32_t *identifierCount)
1871 {
1872 return sBrowserFuncs->enumerate(instance, npobj, identifiers,
1873 identifierCount);
1874 }
1876 bool
1877 NPN_GetProperty(NPP instance,
1878 NPObject *npobj,
1879 NPIdentifier propertyName,
1880 NPVariant *result)
1881 {
1882 return sBrowserFuncs->getproperty(instance, npobj, propertyName, result);
1883 }
1885 bool
1886 NPN_Evaluate(NPP instance, NPObject *npobj, NPString *script, NPVariant *result)
1887 {
1888 return sBrowserFuncs->evaluate(instance, npobj, script, result);
1889 }
1891 void
1892 NPN_SetException(NPObject *npobj, const NPUTF8 *message)
1893 {
1894 return sBrowserFuncs->setexception(npobj, message);
1895 }
1897 NPBool
1898 NPN_ConvertPoint(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace)
1899 {
1900 return sBrowserFuncs->convertpoint(instance, sourceX, sourceY, sourceSpace, destX, destY, destSpace);
1901 }
1903 NPError
1904 NPN_SetValueForURL(NPP instance, NPNURLVariable variable, const char *url, const char *value, uint32_t len)
1905 {
1906 return sBrowserFuncs->setvalueforurl(instance, variable, url, value, len);
1907 }
1909 NPError
1910 NPN_GetValueForURL(NPP instance, NPNURLVariable variable, const char *url, char **value, uint32_t *len)
1911 {
1912 return sBrowserFuncs->getvalueforurl(instance, variable, url, value, len);
1913 }
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)
1924 {
1925 return sBrowserFuncs->getauthenticationinfo(instance, protocol, host, port, scheme, realm,
1926 username, ulen, password, plen);
1927 }
1929 void
1930 NPN_PluginThreadAsyncCall(NPP plugin, void (*func)(void*), void* userdata)
1931 {
1932 return sBrowserFuncs->pluginthreadasynccall(plugin, func, userdata);
1933 }
1935 void
1936 NPN_URLRedirectResponse(NPP instance, void* notifyData, NPBool allow)
1937 {
1938 return sBrowserFuncs->urlredirectresponse(instance, notifyData, allow);
1939 }
1941 NPError
1942 NPN_InitAsyncSurface(NPP instance, NPSize *size, NPImageFormat format,
1943 void *initData, NPAsyncSurface *surface)
1944 {
1945 return sBrowserFuncs->initasyncsurface(instance, size, format, initData, surface);
1946 }
1948 NPError
1949 NPN_FinalizeAsyncSurface(NPP instance, NPAsyncSurface *surface)
1950 {
1951 return sBrowserFuncs->finalizeasyncsurface(instance, surface);
1952 }
1954 void
1955 NPN_SetCurrentAsyncSurface(NPP instance, NPAsyncSurface *surface, NPRect *changed)
1956 {
1957 sBrowserFuncs->setcurrentasyncsurface(instance, surface, changed);
1958 }
1960 //
1961 // npruntime object functions
1962 //
1964 NPObject*
1965 scriptableAllocate(NPP npp, NPClass* aClass)
1966 {
1967 TestNPObject* object = (TestNPObject*)NPN_MemAlloc(sizeof(TestNPObject));
1968 if (!object)
1969 return nullptr;
1970 memset(object, 0, sizeof(TestNPObject));
1971 return object;
1972 }
1974 void
1975 scriptableDeallocate(NPObject* npobj)
1976 {
1977 NPN_MemFree(npobj);
1978 }
1980 void
1981 scriptableInvalidate(NPObject* npobj)
1982 {
1983 }
1985 bool
1986 scriptableHasMethod(NPObject* npobj, NPIdentifier name)
1987 {
1988 for (int i = 0; i < int(ARRAY_LENGTH(sPluginMethodIdentifiers)); i++) {
1989 if (name == sPluginMethodIdentifiers[i])
1990 return true;
1991 }
1992 return false;
1993 }
1995 bool
1996 scriptableInvoke(NPObject* npobj, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result)
1997 {
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);
2004 }
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);
2009 }
2010 }
2011 return false;
2012 }
2014 for (int i = 0; i < int(ARRAY_LENGTH(sPluginMethodIdentifiers)); i++) {
2015 if (name == sPluginMethodIdentifiers[i])
2016 return sPluginMethodFunctions[i](npobj, args, argCount, result);
2017 }
2018 return false;
2019 }
2021 bool
2022 scriptableInvokeDefault(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2023 {
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);
2030 }
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);
2035 }
2036 }
2037 return false;
2038 }
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;
2051 }
2052 case NPVariantType_Void:
2053 value << ";undefined";
2054 break;
2055 case NPVariantType_Null:
2056 value << ";null";
2057 break;
2058 default:
2059 value << ";other";
2060 }
2061 }
2063 char *outval = NPN_StrDup(value.str().c_str());
2064 STRINGZ_TO_NPVARIANT(outval, *result);
2065 return true;
2066 }
2068 bool
2069 scriptableHasProperty(NPObject* npobj, NPIdentifier name)
2070 {
2071 if (NPN_IdentifierIsString(name)) {
2072 NPUTF8 *asUTF8 = NPN_UTF8FromIdentifier(name);
2073 if (NPN_GetStringIdentifier(asUTF8) != name) {
2074 Crash();
2075 }
2076 NPN_MemFree(asUTF8);
2077 }
2078 else {
2079 if (NPN_GetIntIdentifier(NPN_IntFromIdentifier(name)) != name) {
2080 Crash();
2081 }
2082 }
2083 for (int i = 0; i < int(ARRAY_LENGTH(sPluginPropertyIdentifiers)); i++) {
2084 if (name == sPluginPropertyIdentifiers[i]) {
2085 return true;
2086 }
2087 }
2088 return false;
2089 }
2091 bool
2092 scriptableGetProperty(NPObject* npobj, NPIdentifier name, NPVariant* result)
2093 {
2094 for (int i = 0; i < int(ARRAY_LENGTH(sPluginPropertyIdentifiers)); i++) {
2095 if (name == sPluginPropertyIdentifiers[i]) {
2096 DuplicateNPVariant(*result, sPluginPropertyValues[i]);
2097 return true;
2098 }
2099 }
2100 return false;
2101 }
2103 bool
2104 scriptableSetProperty(NPObject* npobj, NPIdentifier name, const NPVariant* value)
2105 {
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;
2111 }
2112 }
2113 return false;
2114 }
2116 bool
2117 scriptableRemoveProperty(NPObject* npobj, NPIdentifier name)
2118 {
2119 for (int i = 0; i < int(ARRAY_LENGTH(sPluginPropertyIdentifiers)); i++) {
2120 if (name == sPluginPropertyIdentifiers[i]) {
2121 NPN_ReleaseVariantValue(&sPluginPropertyValues[i]);
2122 return true;
2123 }
2124 }
2125 return false;
2126 }
2128 bool
2129 scriptableEnumerate(NPObject* npobj, NPIdentifier** identifier, uint32_t* count)
2130 {
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;
2140 }
2142 bool
2143 scriptableConstruct(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2144 {
2145 return false;
2146 }
2148 //
2149 // test functions
2150 //
2152 static bool
2153 compareVariants(NPP instance, const NPVariant* var1, const NPVariant* var2)
2154 {
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;
2161 }
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;
2171 }
2172 break;
2173 }
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;
2180 }
2181 break;
2182 }
2183 case NPVariantType_Void: {
2184 // void values are always equivalent
2185 break;
2186 }
2187 case NPVariantType_Null: {
2188 // null values are always equivalent
2189 break;
2190 }
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;
2197 }
2198 break;
2199 }
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;
2209 }
2210 break;
2211 }
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;
2222 }
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;
2229 }
2230 else {
2231 if (!NPN_HasProperty(instance, result, identifiers[i])) {
2232 id->err << "NPN_HasProperty returned false";
2233 success = false;
2234 }
2235 else {
2236 if (!NPN_GetProperty(instance, result, identifiers[i],
2237 &resultVariant)) {
2238 id->err << "NPN_GetProperty 2 returned false";
2239 success = false;
2240 }
2241 else {
2242 success = compareVariants(instance, &resultVariant,
2243 &expectedVariant);
2244 NPN_ReleaseVariantValue(&expectedVariant);
2245 }
2246 }
2247 NPN_ReleaseVariantValue(&resultVariant);
2248 }
2249 }
2250 break;
2251 }
2252 default:
2253 id->err << "Unknown variant type";
2254 success = false;
2255 }
2257 return success;
2258 }
2260 static bool
2261 throwExceptionNextInvoke(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2262 {
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;
2268 }
2270 static bool
2271 npnInvokeDefaultTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2272 {
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;
2296 }
2297 }
2298 }
2299 NPN_ReleaseVariantValue(&objectVariant);
2300 }
2302 NPN_ReleaseObject(windowObject);
2303 return success;
2304 }
2306 static bool
2307 npnInvokeTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2308 {
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;
2334 }
2336 static bool
2337 npnEvaluateTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2338 {
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;
2357 }
2359 static bool
2360 setUndefinedValueTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2361 {
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;
2366 }
2368 static bool
2369 identifierToStringTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2370 {
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;
2382 }
2384 static bool
2385 queryPrivateModeState(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2386 {
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;
2394 }
2396 static bool
2397 lastReportedPrivateModeState(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2398 {
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;
2405 }
2407 static bool
2408 hasWidget(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2409 {
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;
2416 }
2418 static bool
2419 getEdge(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2420 {
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;
2435 }
2437 static bool
2438 getClipRegionRectCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2439 {
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;
2449 }
2451 static bool
2452 getClipRegionRectEdge(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2453 {
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;
2473 }
2475 static bool
2476 startWatchingInstanceCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2477 {
2478 if (argCount != 0)
2479 return false;
2480 if (sWatchingInstanceCount)
2481 return false;
2483 sWatchingInstanceCount = true;
2484 sInstanceCount = 0;
2485 ++sCurrentInstanceCountWatchGeneration;
2486 return true;
2487 }
2489 static bool
2490 getInstanceCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2491 {
2492 if (argCount != 0)
2493 return false;
2494 if (!sWatchingInstanceCount)
2495 return false;
2497 INT32_TO_NPVARIANT(sInstanceCount, *result);
2498 return true;
2499 }
2501 static bool
2502 stopWatchingInstanceCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2503 {
2504 if (argCount != 0)
2505 return false;
2506 if (!sWatchingInstanceCount)
2507 return false;
2509 sWatchingInstanceCount = false;
2510 return true;
2511 }
2513 static bool
2514 getLastMouseX(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2515 {
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;
2523 }
2525 static bool
2526 getLastMouseY(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2527 {
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;
2535 }
2537 static bool
2538 getPaintCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2539 {
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;
2547 }
2549 static bool
2550 getWidthAtLastPaint(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2551 {
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;
2559 }
2561 static bool
2562 setInvalidateDuringPaint(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2563 {
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;
2575 }
2577 static bool
2578 setSlowPaint(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2579 {
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;
2591 }
2593 static bool
2594 getError(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2595 {
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);
2607 }
2608 return true;
2609 }
2611 static bool
2612 doInternalConsistencyCheck(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2613 {
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;
2624 }
2625 memcpy(utf8String, error.c_str(), error.length() + 1);
2626 STRINGZ_TO_NPVARIANT(utf8String, *result);
2627 return true;
2628 }
2630 static bool
2631 convertPointX(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2632 {
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;
2659 }
2661 static bool
2662 convertPointY(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2663 {
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;
2690 }
2692 static bool
2693 streamTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2694 {
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]);
2712 }
2713 else {
2714 if (!NPVARIANT_IS_NULL(args[2])) {
2715 return false;
2716 }
2717 }
2719 NPObject* writeCallback = nullptr;
2720 if (NPVARIANT_IS_OBJECT(args[3])) {
2721 writeCallback = NPVARIANT_TO_OBJECT(args[3]);
2722 }
2723 else {
2724 if (!NPVARIANT_IS_NULL(args[3])) {
2725 return false;
2726 }
2727 }
2729 NPObject* notifyCallback = nullptr;
2730 if (NPVARIANT_IS_OBJECT(args[4])) {
2731 notifyCallback = NPVARIANT_TO_OBJECT(args[4]);
2732 }
2733 else {
2734 if (!NPVARIANT_IS_NULL(args[4])) {
2735 return false;
2736 }
2737 }
2739 NPObject* redirectCallback = nullptr;
2740 if (NPVARIANT_IS_OBJECT(args[5])) {
2741 redirectCallback = NPVARIANT_TO_OBJECT(args[5]);
2742 }
2743 else {
2744 if (!NPVARIANT_IS_NULL(args[5])) {
2745 return false;
2746 }
2747 }
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);
2772 }
2773 else {
2774 err = NPN_GetURLNotify(npp, urlstr, nullptr, ndata);
2775 }
2777 free(urlstr);
2779 if (NPERR_NO_ERROR == err) {
2780 if (ndata->writeCallback) {
2781 NPN_RetainObject(ndata->writeCallback);
2782 }
2783 if (ndata->notifyCallback) {
2784 NPN_RetainObject(ndata->notifyCallback);
2785 }
2786 if (ndata->redirectCallback) {
2787 NPN_RetainObject(ndata->redirectCallback);
2788 }
2789 BOOLEAN_TO_NPVARIANT(true, *result);
2790 }
2791 else {
2792 delete ndata;
2793 BOOLEAN_TO_NPVARIANT(false, *result);
2794 }
2796 return true;
2797 }
2799 static bool
2800 setPluginWantsAllStreams(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2801 {
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;
2815 }
2817 static bool
2818 crashPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2819 {
2820 IntentionalCrash();
2821 VOID_TO_NPVARIANT(*result);
2822 return true;
2823 }
2825 static bool
2826 crashOnDestroy(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2827 {
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;
2834 }
2836 static bool
2837 setColor(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2838 {
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);
2860 }
2861 #ifdef XP_WIN
2862 else if (id->asyncDrawing == AD_DXGI) {
2863 pluginDrawAsyncDxgiColor(id);
2864 }
2865 #endif
2867 VOID_TO_NPVARIANT(*result);
2868 return true;
2869 }
2871 void notifyDidPaint(InstanceData* instanceData)
2872 {
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);
2883 }
2885 if (instanceData->slowPaint) {
2886 XPSleep(1);
2887 }
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 ¶m, 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);
2908 }
2909 }
2911 NPN_ReleaseVariantValue(&result);
2912 NPN_ReleaseObject(o);
2913 }
2914 }
2915 }
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)
2923 {
2924 if (argCount != 0) {
2925 return false;
2926 }
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;
2934 }
2936 static bool getObjectValue(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2937 {
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;
2947 }
2949 static bool checkObjectValue(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2950 {
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;
2963 }
2965 static bool enableFPExceptions(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
2966 {
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
2975 }
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';
3000 }
3001 }
3002 NPN_ReleaseVariantValue(&hrefVariant);
3003 }
3004 }
3005 NPN_ReleaseVariantValue(&locationVariant);
3006 }
3008 NPN_ReleaseObject(windowObject);
3010 return outString;
3011 }
3013 static bool
3014 setCookie(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
3015 {
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);
3031 }
3033 static bool
3034 getCookie(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
3035 {
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;
3053 }
3055 static bool
3056 getAuthInfo(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
3057 {
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;
3091 }
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;
3105 }
3107 static void timerCallback(NPP npp, uint32_t timerID)
3108 {
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;
3121 }
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);
3128 }
3130 NPN_ReleaseObject(windowObject);
3132 if (event.timerIdSchedule > -1) {
3133 id->timerID[event.timerIdSchedule] = NPN_ScheduleTimer(npp, event.timerInterval, event.timerRepeat, timerCallback);
3134 }
3135 if (event.timerIdUnschedule > -1) {
3136 NPN_UnscheduleTimer(npp, id->timerID[event.timerIdUnschedule]);
3137 }
3138 }
3140 static bool
3141 timerTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
3142 {
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;
3158 }
3160 #ifdef XP_WIN
3161 void
3162 ThreadProc(void* cookie)
3163 #else
3164 void*
3165 ThreadProc(void* cookie)
3166 #endif
3167 {
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
3176 }
3178 void
3179 asyncCallback(void* cookie)
3180 {
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;
3210 }
3211 }
3213 static bool
3214 asyncCallbackTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
3215 {
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;
3229 }
3231 static bool
3232 GCRaceInvoke(NPObject*, NPIdentifier, const NPVariant*, uint32_t, NPVariant*)
3233 {
3234 return false;
3235 }
3237 static bool
3238 GCRaceInvokeDefault(NPObject* o, const NPVariant* args, uint32_t argCount,
3239 NPVariant* result)
3240 {
3241 if (1 != argCount || !NPVARIANT_IS_INT32(args[0]) ||
3242 35 != NPVARIANT_TO_INT32(args[0]))
3243 return false;
3245 return true;
3246 }
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
3265 {
3266 GCRaceData(NPP npp, NPObject* callback, NPObject* localFunc)
3267 : npp_(npp)
3268 , callback_(callback)
3269 , localFunc_(localFunc)
3270 {
3271 NPN_RetainObject(callback_);
3272 NPN_RetainObject(localFunc_);
3273 }
3275 ~GCRaceData()
3276 {
3277 NPN_ReleaseObject(callback_);
3278 NPN_ReleaseObject(localFunc_);
3279 }
3281 NPP npp_;
3282 NPObject* callback_;
3283 NPObject* localFunc_;
3284 };
3286 static void
3287 FinishGCRace(void* closure)
3288 {
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;
3303 }
3305 bool
3306 checkGCRace(NPObject* npobj, const NPVariant* args, uint32_t argCount,
3307 NPVariant* result)
3308 {
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;
3323 }
3325 bool
3326 hangPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount,
3327 NPVariant* result)
3328 {
3329 mozilla::NoteIntentionalCrash("plugin");
3331 bool busyHang = false;
3332 if ((argCount == 1) && NPVARIANT_IS_BOOLEAN(args[0])) {
3333 busyHang = NPVARIANT_TO_BOOLEAN(args[0]);
3334 }
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++;
3342 }
3343 }
3344 } else {
3345 #ifdef XP_WIN
3346 Sleep(100000000);
3347 Sleep(100000000);
3348 #else
3349 pause();
3350 pause();
3351 #endif
3352 }
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;
3359 }
3361 bool
3362 stallPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount,
3363 NPVariant* result)
3364 {
3365 uint32_t stallTimeSeconds = 0;
3366 if ((argCount == 1) && NPVARIANT_IS_INT32(args[0])) {
3367 stallTimeSeconds = (uint32_t) NPVARIANT_TO_INT32(args[0]);
3368 }
3370 #ifdef XP_WIN
3371 Sleep(stallTimeSeconds * 1000U);
3372 #else
3373 sleep(stallTimeSeconds);
3374 #endif
3376 return true;
3377 }
3379 #if defined(MOZ_WIDGET_GTK)
3380 bool
3381 getClipboardText(NPObject* npobj, const NPVariant* args, uint32_t argCount,
3382 NPVariant* result)
3383 {
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;
3400 }
3402 bool
3403 crashPluginInNestedLoop(NPObject* npobj, const NPVariant* args,
3404 uint32_t argCount, NPVariant* result)
3405 {
3406 NPP npp = static_cast<TestNPObject*>(npobj)->npp;
3407 InstanceData* id = static_cast<InstanceData*>(npp->pdata);
3408 return pluginCrashInNestedLoop(id);
3409 }
3411 bool
3412 destroySharedGfxStuff(NPObject* npobj, const NPVariant* args,
3413 uint32_t argCount, NPVariant* result)
3414 {
3415 NPP npp = static_cast<TestNPObject*>(npobj)->npp;
3416 InstanceData* id = static_cast<InstanceData*>(npp->pdata);
3417 return pluginDestroySharedGfxStuff(id);
3418 }
3420 #else
3421 bool
3422 getClipboardText(NPObject* npobj, const NPVariant* args, uint32_t argCount,
3423 NPVariant* result)
3424 {
3425 // XXX Not implemented!
3426 return false;
3427 }
3429 bool
3430 crashPluginInNestedLoop(NPObject* npobj, const NPVariant* args,
3431 uint32_t argCount, NPVariant* result)
3432 {
3433 // XXX Not implemented!
3434 return false;
3435 }
3437 bool
3438 destroySharedGfxStuff(NPObject* npobj, const NPVariant* args,
3439 uint32_t argCount, NPVariant* result)
3440 {
3441 // XXX Not implemented!
3442 return false;
3443 }
3444 #endif
3446 bool
3447 callOnDestroy(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
3448 {
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;
3462 }
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)
3469 {
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;
3481 }
3483 bool
3484 propertyAndMethod(NPObject* npobj, const NPVariant* args, uint32_t argCount,
3485 NPVariant* result)
3486 {
3487 INT32_TO_NPVARIANT(5, *result);
3488 return true;
3489 }
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)
3498 {
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;
3508 }
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);
3514 }
3516 return true;
3517 }
3519 bool
3520 getTopLevelWindowActivationEventCount(NPObject* npobj, const NPVariant* args, uint32_t argCount,
3521 NPVariant* result)
3522 {
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;
3532 }
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)
3541 {
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;
3551 }
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);
3557 }
3559 return true;
3560 }
3562 bool
3563 getFocusEventCount(NPObject* npobj, const NPVariant* args, uint32_t argCount,
3564 NPVariant* result)
3565 {
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;
3575 }
3577 bool
3578 getEventModel(NPObject* npobj, const NPVariant* args, uint32_t argCount,
3579 NPVariant* result)
3580 {
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;
3590 }
3592 static bool
3593 ReflectorHasMethod(NPObject* npobj, NPIdentifier name)
3594 {
3595 return false;
3596 }
3598 static bool
3599 ReflectorHasProperty(NPObject* npobj, NPIdentifier name)
3600 {
3601 return true;
3602 }
3604 static bool
3605 ReflectorGetProperty(NPObject* npobj, NPIdentifier name, NPVariant* result)
3606 {
3607 if (NPN_IdentifierIsString(name)) {
3608 char* s = NPN_UTF8FromIdentifier(name);
3609 STRINGZ_TO_NPVARIANT(s, *result);
3610 return true;
3611 }
3613 INT32_TO_NPVARIANT(NPN_IntFromIdentifier(name), *result);
3614 return true;
3615 }
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)
3635 {
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;
3646 }
3648 bool isVisible(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
3649 {
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;
3658 }
3660 bool getWindowPosition(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
3661 {
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;
3682 }
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;
3696 }
3698 bool constructObject(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
3699 {
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);
3708 }
3710 bool setSitesWithData(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
3711 {
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;
3749 }
3751 return true;
3752 }
3754 bool setSitesWithDataCapabilities(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
3755 {
3756 if (argCount != 1 || !NPVARIANT_IS_BOOLEAN(args[0]))
3757 return false;
3759 sClearByAgeSupported = NPVARIANT_TO_BOOLEAN(args[0]);
3760 return true;
3761 }
3763 bool getLastKeyText(NPObject* npobj, const NPVariant* args, uint32_t argCount,
3764 NPVariant* result)
3765 {
3766 if (argCount != 0) {
3767 return false;
3768 }
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;
3776 }
3778 bool getNPNVdocumentOrigin(NPObject* npobj, const NPVariant* args, uint32_t argCount,
3779 NPVariant* result)
3780 {
3781 if (argCount != 0) {
3782 return false;
3783 }
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;
3791 }
3793 STRINGZ_TO_NPVARIANT(origin, *result);
3794 return true;
3795 }
3797 bool getMouseUpEventCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
3798 {
3799 if (argCount != 0) {
3800 return false;
3801 }
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;
3807 }
3809 bool queryContentsScaleFactor(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
3810 {
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;
3820 }
3821 #endif
3822 DOUBLE_TO_NPVARIANT(scaleFactor, *result);
3823 return true;
3824 }