Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / modules / plugin / base / src / nsNPAPIPlugin.cpp
blobcbe0d5a8d7fb5a81031e3606090d9e04584a21f1
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Josh Aas <josh@mozilla.com>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "prtypes.h"
40 #include "prmem.h"
41 #include "prclist.h"
42 #include "nsAutoLock.h"
43 #include "nsNPAPIPlugin.h"
44 #include "nsNPAPIPluginInstance.h"
45 #include "nsNPAPIPluginStreamListener.h"
46 #include "nsIServiceManager.h"
47 #include "nsThreadUtils.h"
49 #include "nsIPluginStreamListener.h"
50 #include "nsPluginsDir.h"
51 #include "nsPluginSafety.h"
52 #include "nsIPrefService.h"
53 #include "nsIPrefBranch.h"
54 #include "nsPluginLogging.h"
56 #include "nsIPluginInstancePeer2.h"
57 #include "nsIJSContextStack.h"
59 #include "nsPIPluginInstancePeer.h"
60 #include "nsIDOMElement.h"
61 #include "nsIDOMDocument.h"
62 #include "nsPIDOMWindow.h"
63 #include "nsIDocument.h"
64 #include "nsIScriptGlobalObject.h"
65 #include "nsIScriptContext.h"
66 #include "nsDOMJSUtils.h"
67 #include "nsIPrincipal.h"
69 #include "jscntxt.h"
71 #include "nsIXPConnect.h"
73 #include "nsIObserverService.h"
74 #include <prinrval.h>
76 #ifdef XP_MACOSX
77 #include <Carbon/Carbon.h>
78 #endif
80 // needed for nppdf plugin
81 #ifdef MOZ_WIDGET_GTK2
82 #include <gdk/gdk.h>
83 #include <gdk/gdkx.h>
84 #include "gtk2xtbin.h"
85 #endif
87 #include "nsJSNPRuntime.h"
89 static PRLock *sPluginThreadAsyncCallLock = nsnull;
90 static PRCList sPendingAsyncCalls = PR_INIT_STATIC_CLIST(&sPendingAsyncCalls);
92 // POST/GET stream type
93 enum eNPPStreamTypeInternal {
94 eNPPStreamTypeInternal_Get,
95 eNPPStreamTypeInternal_Post
98 static NS_DEFINE_IID(kCPluginManagerCID, NS_PLUGINMANAGER_CID);
99 static NS_DEFINE_IID(kPluginManagerCID, NS_PLUGINMANAGER_CID);
100 static NS_DEFINE_IID(kMemoryCID, NS_MEMORY_CID);
102 // Static stub functions that are exported to the 4.x plugin as entry
103 // points via the CALLBACKS variable.
104 PR_BEGIN_EXTERN_C
106 static NPError NP_CALLBACK
107 _requestread(NPStream *pstream, NPByteRange *rangeList);
109 static NPError NP_CALLBACK
110 _geturlnotify(NPP npp, const char* relativeURL, const char* target,
111 void* notifyData);
113 static NPError NP_CALLBACK
114 _getvalue(NPP npp, NPNVariable variable, void *r_value);
116 static NPError NP_CALLBACK
117 _setvalue(NPP npp, NPPVariable variable, void *r_value);
119 static NPError NP_CALLBACK
120 _geturl(NPP npp, const char* relativeURL, const char* target);
122 static NPError NP_CALLBACK
123 _posturlnotify(NPP npp, const char* relativeURL, const char *target,
124 uint32_t len, const char *buf, NPBool file, void* notifyData);
126 static NPError NP_CALLBACK
127 _posturl(NPP npp, const char* relativeURL, const char *target, uint32_t len,
128 const char *buf, NPBool file);
130 static NPError NP_CALLBACK
131 _newstream(NPP npp, NPMIMEType type, const char* window, NPStream** pstream);
133 static int32_t NP_CALLBACK
134 _write(NPP npp, NPStream *pstream, int32_t len, void *buffer);
136 static NPError NP_CALLBACK
137 _destroystream(NPP npp, NPStream *pstream, NPError reason);
139 static void NP_CALLBACK
140 _status(NPP npp, const char *message);
142 static void NP_CALLBACK
143 _memfree (void *ptr);
145 static uint32_t NP_CALLBACK
146 _memflush(uint32_t size);
148 static void NP_CALLBACK
149 _reloadplugins(NPBool reloadPages);
151 static void NP_CALLBACK
152 _invalidaterect(NPP npp, NPRect *invalidRect);
154 static void NP_CALLBACK
155 _invalidateregion(NPP npp, NPRegion invalidRegion);
157 static void NP_CALLBACK
158 _forceredraw(NPP npp);
160 static void NP_CALLBACK
161 _pushpopupsenabledstate(NPP npp, NPBool enabled);
163 static void NP_CALLBACK
164 _poppopupsenabledstate(NPP npp);
166 typedef void(*PluginThreadCallback)(void *);
167 static void NP_CALLBACK
168 _pluginthreadasynccall(NPP instance, PluginThreadCallback func,
169 void *userData);
171 static const char* NP_CALLBACK
172 _useragent(NPP npp);
174 static void* NP_CALLBACK
175 _memalloc (uint32_t size);
177 // Deprecated entry points for the old Java plugin.
178 static void* NP_CALLBACK /* OJI type: JRIEnv* */
179 _getJavaEnv(void);
180 static void* NP_CALLBACK /* OJI type: jref */
181 _getJavaPeer(NPP npp);
183 PR_END_EXTERN_C
185 // This function sends a notification using the observer service to any object
186 // registered to listen to the "experimental-notify-plugin-call" subject.
187 // Each "experimental-notify-plugin-call" notification carries with it the run
188 // time value in milliseconds that the call took to execute.
189 void NS_NotifyPluginCall(PRIntervalTime startTime)
191 PRIntervalTime endTime = PR_IntervalNow() - startTime;
192 nsCOMPtr<nsIObserverService> notifyUIService =
193 do_GetService("@mozilla.org/observer-service;1");
194 float runTimeInSeconds = float(endTime) / PR_TicksPerSecond();
195 nsAutoString runTimeString;
196 runTimeString.AppendFloat(runTimeInSeconds);
197 const PRUnichar* runTime = runTimeString.get();
198 notifyUIService->NotifyObservers(nsnull, "experimental-notify-plugin-call",
199 runTime);
202 NPNetscapeFuncs nsNPAPIPlugin::CALLBACKS;
204 void
205 nsNPAPIPlugin::CheckClassInitialized(void)
207 static PRBool initialized = PR_FALSE;
209 if (initialized)
210 return;
212 // XXX It'd be nice to make this const and initialize it statically...
213 CALLBACKS.size = sizeof(CALLBACKS);
214 CALLBACKS.version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;
215 CALLBACKS.geturl = ((NPN_GetURLProcPtr)_geturl);
216 CALLBACKS.posturl = ((NPN_PostURLProcPtr)_posturl);
217 CALLBACKS.requestread = ((NPN_RequestReadProcPtr)_requestread);
218 CALLBACKS.newstream = ((NPN_NewStreamProcPtr)_newstream);
219 CALLBACKS.write = ((NPN_WriteProcPtr)_write);
220 CALLBACKS.destroystream = ((NPN_DestroyStreamProcPtr)_destroystream);
221 CALLBACKS.status = ((NPN_StatusProcPtr)_status);
222 CALLBACKS.uagent = ((NPN_UserAgentProcPtr)_useragent);
223 CALLBACKS.memalloc = ((NPN_MemAllocProcPtr)_memalloc);
224 CALLBACKS.memfree = ((NPN_MemFreeProcPtr)_memfree);
225 CALLBACKS.memflush = ((NPN_MemFlushProcPtr)_memflush);
226 CALLBACKS.reloadplugins = ((NPN_ReloadPluginsProcPtr)_reloadplugins);
228 // Deprecated API callbacks.
229 CALLBACKS.getJavaEnv = ((NPN_GetJavaEnvProcPtr)_getJavaEnv);
230 CALLBACKS.getJavaPeer = ((NPN_GetJavaPeerProcPtr)_getJavaPeer);
231 CALLBACKS.geturlnotify = ((NPN_GetURLNotifyProcPtr)_geturlnotify);
232 CALLBACKS.posturlnotify = ((NPN_PostURLNotifyProcPtr)_posturlnotify);
233 CALLBACKS.getvalue = ((NPN_GetValueProcPtr)_getvalue);
234 CALLBACKS.setvalue = ((NPN_SetValueProcPtr)_setvalue);
235 CALLBACKS.invalidaterect = ((NPN_InvalidateRectProcPtr)_invalidaterect);
236 CALLBACKS.invalidateregion = ((NPN_InvalidateRegionProcPtr)_invalidateregion);
237 CALLBACKS.forceredraw = ((NPN_ForceRedrawProcPtr)_forceredraw);
238 CALLBACKS.getstringidentifier = ((NPN_GetStringIdentifierProcPtr)_getstringidentifier);
239 CALLBACKS.getstringidentifiers = ((NPN_GetStringIdentifiersProcPtr)_getstringidentifiers);
240 CALLBACKS.getintidentifier = ((NPN_GetIntIdentifierProcPtr)_getintidentifier);
241 CALLBACKS.identifierisstring = ((NPN_IdentifierIsStringProcPtr)_identifierisstring);
242 CALLBACKS.utf8fromidentifier = ((NPN_UTF8FromIdentifierProcPtr)_utf8fromidentifier);
243 CALLBACKS.intfromidentifier = ((NPN_IntFromIdentifierProcPtr)_intfromidentifier);
244 CALLBACKS.createobject = ((NPN_CreateObjectProcPtr)_createobject);
245 CALLBACKS.retainobject = ((NPN_RetainObjectProcPtr)_retainobject);
246 CALLBACKS.releaseobject = ((NPN_ReleaseObjectProcPtr)_releaseobject);
247 CALLBACKS.invoke = ((NPN_InvokeProcPtr)_invoke);
248 CALLBACKS.invokeDefault = ((NPN_InvokeDefaultProcPtr)_invokeDefault);
249 CALLBACKS.evaluate = ((NPN_EvaluateProcPtr)_evaluate);
250 CALLBACKS.getproperty = ((NPN_GetPropertyProcPtr)_getproperty);
251 CALLBACKS.setproperty = ((NPN_SetPropertyProcPtr)_setproperty);
252 CALLBACKS.removeproperty = ((NPN_RemovePropertyProcPtr)_removeproperty);
253 CALLBACKS.hasproperty = ((NPN_HasPropertyProcPtr)_hasproperty);
254 CALLBACKS.hasmethod = ((NPN_HasMethodProcPtr)_hasmethod);
255 CALLBACKS.enumerate = ((NPN_EnumerateProcPtr)_enumerate);
256 CALLBACKS.construct = ((NPN_ConstructProcPtr)_construct);
257 CALLBACKS.releasevariantvalue = ((NPN_ReleaseVariantValueProcPtr)_releasevariantvalue);
258 CALLBACKS.setexception = ((NPN_SetExceptionProcPtr)_setexception);
259 CALLBACKS.pushpopupsenabledstate = ((NPN_PushPopupsEnabledStateProcPtr)_pushpopupsenabledstate);
260 CALLBACKS.poppopupsenabledstate = ((NPN_PopPopupsEnabledStateProcPtr)_poppopupsenabledstate);
261 CALLBACKS.pluginthreadasynccall = ((NPN_PluginThreadAsyncCallProcPtr)_pluginthreadasynccall);
263 if (!sPluginThreadAsyncCallLock)
264 sPluginThreadAsyncCallLock = nsAutoLock::NewLock("sPluginThreadAsyncCallLock");
266 initialized = PR_TRUE;
268 NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,("NPN callbacks initialized\n"));
271 NS_IMPL_ISUPPORTS2(nsNPAPIPlugin, nsIPlugin, nsIFactory)
273 nsNPAPIPlugin::nsNPAPIPlugin(NPPluginFuncs* callbacks, PRLibrary* aLibrary,
274 NP_PLUGINSHUTDOWN aShutdown)
276 memset((void*) &fCallbacks, 0, sizeof(fCallbacks));
277 fLibrary = nsnull;
279 #if defined(XP_WIN) || defined(XP_OS2)
280 // On Windows (and Mac) we need to keep a direct reference to the
281 // fCallbacks and NOT just copy the struct. See Bugzilla 85334
283 NP_GETENTRYPOINTS pfnGetEntryPoints =
284 (NP_GETENTRYPOINTS)PR_FindSymbol(aLibrary, "NP_GetEntryPoints");
286 if (!pfnGetEntryPoints)
287 return;
289 fCallbacks.size = sizeof(fCallbacks);
291 nsresult result = pfnGetEntryPoints(&fCallbacks);
292 NS_ASSERTION(result == NS_OK, "Failed to get callbacks");
294 NS_ASSERTION(HIBYTE(fCallbacks.version) >= NP_VERSION_MAJOR,
295 "callback version is less than NP version");
297 fShutdownEntry = (NP_PLUGINSHUTDOWN)PR_FindSymbol(aLibrary, "NP_Shutdown");
298 #elif defined(XP_MACOSX)
299 NPPluginFuncs np_callbacks;
300 memset((void*) &np_callbacks, 0, sizeof(np_callbacks));
301 np_callbacks.size = sizeof(np_callbacks);
303 fShutdownEntry = (NP_PLUGINSHUTDOWN)PR_FindSymbol(aLibrary, "NP_Shutdown");
304 NP_GETENTRYPOINTS pfnGetEntryPoints = (NP_GETENTRYPOINTS)PR_FindSymbol(aLibrary, "NP_GetEntryPoints");
305 NP_PLUGININIT pfnInitialize = (NP_PLUGININIT)PR_FindSymbol(aLibrary, "NP_Initialize");
306 if (!pfnGetEntryPoints || !pfnInitialize || !fShutdownEntry) {
307 NS_WARNING("Not all necessary functions exposed by plugin, it will not load.");
308 return;
311 // we call NP_Initialize before getting function pointers to match
312 // WebKit's behavior. They implemented this first on Mac OS X.
313 if (pfnInitialize(&(nsNPAPIPlugin::CALLBACKS)) != NPERR_NO_ERROR)
314 return;
315 if (pfnGetEntryPoints(&np_callbacks) != NPERR_NO_ERROR)
316 return;
318 fCallbacks.size = sizeof(fCallbacks);
319 fCallbacks.version = np_callbacks.version;
320 fCallbacks.newp = (NPP_NewProcPtr)np_callbacks.newp;
321 fCallbacks.destroy = (NPP_DestroyProcPtr)np_callbacks.destroy;
322 fCallbacks.setwindow = (NPP_SetWindowProcPtr)np_callbacks.setwindow;
323 fCallbacks.newstream = (NPP_NewStreamProcPtr)np_callbacks.newstream;
324 fCallbacks.destroystream = (NPP_DestroyStreamProcPtr)np_callbacks.destroystream;
325 fCallbacks.asfile = (NPP_StreamAsFileProcPtr)np_callbacks.asfile;
326 fCallbacks.writeready = (NPP_WriteReadyProcPtr)np_callbacks.writeready;
327 fCallbacks.write = (NPP_WriteProcPtr)np_callbacks.write;
328 fCallbacks.print = (NPP_PrintProcPtr)np_callbacks.print;
329 fCallbacks.event = (NPP_HandleEventProcPtr)np_callbacks.event;
330 fCallbacks.urlnotify = (NPP_URLNotifyProcPtr)np_callbacks.urlnotify;
331 fCallbacks.getvalue = (NPP_GetValueProcPtr)np_callbacks.getvalue;
332 fCallbacks.setvalue = (NPP_SetValueProcPtr)np_callbacks.setvalue;
333 #else // for everyone else
334 memcpy((void*) &fCallbacks, (void*) callbacks, sizeof(fCallbacks));
335 fShutdownEntry = aShutdown;
336 #endif
338 fLibrary = aLibrary;
341 nsNPAPIPlugin::~nsNPAPIPlugin(void)
343 // reset the callbacks list
344 memset((void*) &fCallbacks, 0, sizeof(fCallbacks));
348 #if defined(XP_MACOSX)
349 void
350 nsNPAPIPlugin::SetPluginRefNum(short aRefNum)
352 fPluginRefNum = aRefNum;
354 #endif
356 // Creates the nsNPAPIPlugin object. One nsNPAPIPlugin object exists per plugin (not instance).
357 nsresult
358 nsNPAPIPlugin::CreatePlugin(const char* aFileName, const char* aFullPath,
359 PRLibrary* aLibrary, nsIPlugin** aResult)
361 CheckClassInitialized();
363 #if defined(XP_UNIX) && !defined(XP_MACOSX)
364 nsNPAPIPlugin *plptr;
366 NPPluginFuncs callbacks;
367 memset((void*) &callbacks, 0, sizeof(callbacks));
368 callbacks.size = sizeof(callbacks);
370 NP_PLUGINSHUTDOWN pfnShutdown =
371 (NP_PLUGINSHUTDOWN)PR_FindFunctionSymbol(aLibrary, "NP_Shutdown");
373 // create the new plugin handler
374 *aResult = plptr =
375 new nsNPAPIPlugin(&callbacks, aLibrary, pfnShutdown);
377 if (*aResult == NULL)
378 return NS_ERROR_OUT_OF_MEMORY;
380 NS_ADDREF(*aResult);
382 if (!aFileName) //do not call NP_Initialize in this case, bug 74938
383 return NS_OK;
385 // we must init here because the plugin may call NPN functions
386 // when we call into the NP_Initialize entry point - NPN functions
387 // require that mBrowserManager be set up
388 plptr->Initialize();
390 NP_PLUGINUNIXINIT pfnInitialize =
391 (NP_PLUGINUNIXINIT)PR_FindFunctionSymbol(aLibrary, "NP_Initialize");
393 if (!pfnInitialize)
394 return NS_ERROR_UNEXPECTED;
396 if (pfnInitialize(&(nsNPAPIPlugin::CALLBACKS),&callbacks) != NS_OK)
397 return NS_ERROR_UNEXPECTED;
399 // now copy function table back to nsNPAPIPlugin instance
400 memcpy((void*) &(plptr->fCallbacks), (void*)&callbacks, sizeof(callbacks));
401 #endif
403 #ifdef XP_WIN
404 // Note: on Windows, we must use the fCallback because plugins may
405 // change the function table. The Shockwave installer makes changes
406 // in the table while running
407 *aResult = new nsNPAPIPlugin(nsnull, aLibrary, nsnull);
409 if (*aResult == NULL)
410 return NS_ERROR_OUT_OF_MEMORY;
412 NS_ADDREF(*aResult);
414 // we must init here because the plugin may call NPN functions
415 // when we call into the NP_Initialize entry point - NPN functions
416 // require that mBrowserManager be set up
417 if (NS_FAILED((*aResult)->Initialize())) {
418 NS_RELEASE(*aResult);
419 return NS_ERROR_FAILURE;
422 NP_PLUGININIT pfnInitialize =
423 (NP_PLUGININIT)PR_FindSymbol(aLibrary, "NP_Initialize");
425 if (!pfnInitialize)
426 return NS_ERROR_UNEXPECTED;
428 if (pfnInitialize(&(nsNPAPIPlugin::CALLBACKS)) != NS_OK)
429 return NS_ERROR_UNEXPECTED;
430 #endif
432 #ifdef XP_OS2
433 // create the new plugin handler
434 *aResult = new nsNPAPIPlugin(nsnull, aLibrary, nsnull);
436 if (*aResult == NULL)
437 return NS_ERROR_OUT_OF_MEMORY;
439 NS_ADDREF(*aResult);
441 // we must init here because the plugin may call NPN functions
442 // when we call into the NP_Initialize entry point - NPN functions
443 // require that mBrowserManager be set up
444 if (NS_FAILED((*aResult)->Initialize())) {
445 NS_RELEASE(*aResult);
446 return NS_ERROR_FAILURE;
449 NP_PLUGININIT pfnInitialize =
450 (NP_PLUGININIT)PR_FindSymbol(aLibrary, "NP_Initialize");
452 if (!pfnInitialize)
453 return NS_ERROR_UNEXPECTED;
455 // Fixes problem where the OS/2 native multimedia plugins weren't
456 // working on mozilla though did work on 4.x. Problem is that they
457 // expect the current working directory to be the plugins dir.
458 // Since these plugins are no longer maintained and they represent
459 // the majority of the OS/2 plugin contingency, we'll have to make
460 // them work here.
462 #define MAP_DISKNUM_TO_LETTER(n) ('A' + (n - 1))
463 #define MAP_LETTER_TO_DISKNUM(c) (toupper(c)-'A'+1)
465 unsigned long origDiskNum, pluginDiskNum, logicalDisk;
467 char pluginPath[CCHMAXPATH], origPath[CCHMAXPATH];
468 strcpy(pluginPath, aFileName);
469 char* slash = strrchr(pluginPath, '\\');
470 *slash = '\0';
472 DosQueryCurrentDisk( &origDiskNum, &logicalDisk );
473 pluginDiskNum = MAP_LETTER_TO_DISKNUM(pluginPath[0]);
475 origPath[0] = MAP_DISKNUM_TO_LETTER(origDiskNum);
476 origPath[1] = ':';
477 origPath[2] = '\\';
479 ULONG len = CCHMAXPATH-3;
480 APIRET rc = DosQueryCurrentDir(0, &origPath[3], &len);
481 NS_ASSERTION(NO_ERROR == rc,"DosQueryCurrentDir failed");
483 BOOL bChangedDir = FALSE;
484 BOOL bChangedDisk = FALSE;
485 if (pluginDiskNum != origDiskNum) {
486 rc = DosSetDefaultDisk(pluginDiskNum);
487 NS_ASSERTION(NO_ERROR == rc,"DosSetDefaultDisk failed");
488 bChangedDisk = TRUE;
491 if (stricmp(origPath, pluginPath) != 0) {
492 rc = DosSetCurrentDir(pluginPath);
493 NS_ASSERTION(NO_ERROR == rc,"DosSetCurrentDir failed");
494 bChangedDir = TRUE;
497 nsresult rv = pfnInitialize(&(nsNPAPIPlugin::CALLBACKS));
499 if (bChangedDisk) {
500 rc= DosSetDefaultDisk(origDiskNum);
501 NS_ASSERTION(NO_ERROR == rc,"DosSetDefaultDisk failed");
503 if (bChangedDir) {
504 rc = DosSetCurrentDir(origPath);
505 NS_ASSERTION(NO_ERROR == rc,"DosSetCurrentDir failed");
508 if (!NS_SUCCEEDED(rv)) {
509 return NS_ERROR_UNEXPECTED;
511 #endif
513 #if defined(XP_MACOSX)
514 short appRefNum = ::CurResFile();
515 short pluginRefNum;
517 nsCOMPtr<nsILocalFile> pluginPath;
518 NS_NewNativeLocalFile(nsDependentCString(aFullPath), PR_TRUE,
519 getter_AddRefs(pluginPath));
521 nsPluginFile pluginFile(pluginPath);
522 pluginRefNum = pluginFile.OpenPluginResource();
524 nsNPAPIPlugin* plugin = new nsNPAPIPlugin(nsnull, aLibrary, nsnull);
525 ::UseResFile(appRefNum);
526 if (!plugin)
527 return NS_ERROR_OUT_OF_MEMORY;
529 *aResult = plugin;
531 NS_ADDREF(*aResult);
532 if (NS_FAILED((*aResult)->Initialize())) {
533 NS_RELEASE(*aResult);
534 return NS_ERROR_FAILURE;
537 plugin->SetPluginRefNum(pluginRefNum);
538 #endif
540 #ifdef XP_BEOS
541 // I just copied UNIX version.
542 // Makoto Hamanaka <VYA04230@nifty.com>
544 nsNPAPIPlugin *plptr;
546 NPPluginFuncs callbacks;
547 memset((void*) &callbacks, 0, sizeof(callbacks));
548 callbacks.size = sizeof(callbacks);
550 NP_PLUGINSHUTDOWN pfnShutdown =
551 (NP_PLUGINSHUTDOWN)PR_FindSymbol(aLibrary, "NP_Shutdown");
553 // create the new plugin handler
554 *aResult = plptr = new nsNPAPIPlugin(&callbacks, aLibrary, pfnShutdown);
556 if (*aResult == NULL)
557 return NS_ERROR_OUT_OF_MEMORY;
559 NS_ADDREF(*aResult);
561 // we must init here because the plugin may call NPN functions
562 // when we call into the NP_Initialize entry point - NPN functions
563 // require that mBrowserManager be set up
564 plptr->Initialize();
566 NP_PLUGINUNIXINIT pfnInitialize =
567 (NP_PLUGINUNIXINIT)PR_FindSymbol(aLibrary, "NP_Initialize");
569 if (!pfnInitialize)
570 return NS_ERROR_FAILURE;
572 if (pfnInitialize(&(nsNPAPIPlugin::CALLBACKS),&callbacks) != NS_OK)
573 return NS_ERROR_FAILURE;
575 // now copy function table back to nsNPAPIPlugin instance
576 memcpy((void*) &(plptr->fCallbacks), (void*)&callbacks, sizeof(callbacks));
577 #endif
579 return NS_OK;
582 nsresult
583 nsNPAPIPlugin::CreateInstance(nsISupports *aOuter, const nsIID &aIID,
584 void **aResult)
586 if (!aResult)
587 return NS_ERROR_NULL_POINTER;
589 *aResult = NULL;
591 // XXX This is suspicuous!
592 nsRefPtr<nsNPAPIPluginInstance> inst =
593 new nsNPAPIPluginInstance(&fCallbacks, fLibrary);
595 if (!inst)
596 return NS_ERROR_OUT_OF_MEMORY;
598 return inst->QueryInterface(aIID, aResult);
601 nsresult
602 nsNPAPIPlugin::LockFactory(PRBool aLock)
604 // Not implemented in simplest case.
605 return NS_OK;
608 NS_METHOD
609 nsNPAPIPlugin::CreatePluginInstance(nsISupports *aOuter, REFNSIID aIID,
610 const char *aPluginMIMEType, void **aResult)
612 return CreateInstance(aOuter, aIID, aResult);
615 nsresult
616 nsNPAPIPlugin::Initialize(void)
618 if (!fLibrary)
619 return NS_ERROR_FAILURE;
620 return NS_OK;
623 nsresult
624 nsNPAPIPlugin::Shutdown(void)
626 NPP_PLUGIN_LOG(PLUGIN_LOG_BASIC,
627 ("NPP Shutdown to be called: this=%p\n", this));
629 if (fShutdownEntry) {
630 #if defined(XP_MACOSX)
631 (*fShutdownEntry)();
632 if (fPluginRefNum > 0)
633 ::CloseResFile(fPluginRefNum);
634 #else
635 NS_TRY_SAFE_CALL_VOID(fShutdownEntry(), fLibrary, nsnull);
636 #endif
637 fShutdownEntry = nsnull;
640 PLUGIN_LOG(PLUGIN_LOG_NORMAL,
641 ("NPAPIPlugin Shutdown done, this=%p", this));
642 return NS_OK;
645 nsresult
646 nsNPAPIPlugin::GetMIMEDescription(const char* *resultingDesc)
648 const char* (*npGetMIMEDescription)() =
649 (const char* (*)()) PR_FindFunctionSymbol(fLibrary, "NP_GetMIMEDescription");
651 *resultingDesc = npGetMIMEDescription ? npGetMIMEDescription() : "";
653 PLUGIN_LOG(PLUGIN_LOG_NORMAL,
654 ("nsNPAPIPlugin::GetMIMEDescription called: this=%p, result=%s\n",
655 this, *resultingDesc));
657 return NS_OK;
660 nsresult
661 nsNPAPIPlugin::GetValue(nsPluginVariable variable, void *value)
663 PLUGIN_LOG(PLUGIN_LOG_NORMAL,
664 ("nsNPAPIPlugin::GetValue called: this=%p, variable=%d\n", this, variable));
666 NPError (*npGetValue)(void*, nsPluginVariable, void*) =
667 (NPError (*)(void*, nsPluginVariable, void*)) PR_FindFunctionSymbol(fLibrary,
668 "NP_GetValue");
670 if (npGetValue && NPERR_NO_ERROR == npGetValue(nsnull, variable, value)) {
671 return NS_OK;
674 return NS_ERROR_FAILURE;
677 // Create a new NPP GET or POST (given in the type argument) url
678 // stream that may have a notify callback
679 NPError
680 MakeNewNPAPIStreamInternal(NPP npp, const char *relativeURL, const char *target,
681 eNPPStreamTypeInternal type,
682 PRBool bDoNotify = PR_FALSE,
683 void *notifyData = nsnull, uint32_t len = 0,
684 const char *buf = nsnull, NPBool file = PR_FALSE)
686 if (!npp)
687 return NPERR_INVALID_INSTANCE_ERROR;
689 PluginDestructionGuard guard(npp);
691 nsIPluginInstance *inst = (nsIPluginInstance *) npp->ndata;
693 NS_ASSERTION(inst, "null instance");
694 if (!inst)
695 return NPERR_INVALID_INSTANCE_ERROR;
697 nsCOMPtr<nsIPluginManager> pm = do_GetService(kPluginManagerCID);
698 NS_ASSERTION(pm, "failed to get plugin manager");
699 if (!pm) return NPERR_GENERIC_ERROR;
701 nsCOMPtr<nsIPluginStreamListener> listener;
702 if (!target)
703 ((nsNPAPIPluginInstance*)inst)->NewNotifyStream(getter_AddRefs(listener),
704 notifyData,
705 bDoNotify, relativeURL);
707 switch (type) {
708 case eNPPStreamTypeInternal_Get:
710 if (NS_FAILED(pm->GetURL(inst, relativeURL, target, listener)))
711 return NPERR_GENERIC_ERROR;
712 break;
714 case eNPPStreamTypeInternal_Post:
716 if (NS_FAILED(pm->PostURL(inst, relativeURL, len, buf, file, target,
717 listener)))
718 return NPERR_GENERIC_ERROR;
719 break;
721 default:
722 NS_ASSERTION(0, "how'd I get here");
725 return NPERR_NO_ERROR;
729 // Static callbacks that get routed back through the new C++ API
732 NPError NP_CALLBACK
733 _geturl(NPP npp, const char* relativeURL, const char* target)
735 if (!NS_IsMainThread()) {
736 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_geturl called from the wrong thread\n"));
737 return NPERR_INVALID_PARAM;
740 NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
741 ("NPN_GetURL: npp=%p, target=%s, url=%s\n", (void *)npp, target,
742 relativeURL));
744 PluginDestructionGuard guard(npp);
746 // Block Adobe Acrobat from loading URLs that are not http:, https:,
747 // or ftp: URLs if the given target is null.
748 if (!target && relativeURL &&
749 (strncmp(relativeURL, "http:", 5) != 0) &&
750 (strncmp(relativeURL, "https:", 6) != 0) &&
751 (strncmp(relativeURL, "ftp:", 4) != 0)) {
752 nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) npp->ndata;
754 const char *name = nsPluginHostImpl::GetPluginName(inst);
756 if (name && strstr(name, "Adobe") && strstr(name, "Acrobat")) {
757 return NPERR_NO_ERROR;
761 return MakeNewNPAPIStreamInternal(npp, relativeURL, target,
762 eNPPStreamTypeInternal_Get);
765 NPError NP_CALLBACK
766 _geturlnotify(NPP npp, const char* relativeURL, const char* target,
767 void* notifyData)
769 if (!NS_IsMainThread()) {
770 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_geturlnotify called from the wrong thread\n"));
771 return NPERR_INVALID_PARAM;
774 NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
775 ("NPN_GetURLNotify: npp=%p, target=%s, notify=%p, url=%s\n", (void*)npp,
776 target, notifyData, relativeURL));
778 PluginDestructionGuard guard(npp);
780 return MakeNewNPAPIStreamInternal(npp, relativeURL, target,
781 eNPPStreamTypeInternal_Get, PR_TRUE,
782 notifyData);
785 NPError NP_CALLBACK
786 _posturlnotify(NPP npp, const char *relativeURL, const char *target,
787 uint32_t len, const char *buf, NPBool file, void *notifyData)
789 if (!NS_IsMainThread()) {
790 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_posturlnotify called from the wrong thread\n"));
791 return NPERR_INVALID_PARAM;
793 NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
794 ("NPN_PostURLNotify: npp=%p, target=%s, len=%d, file=%d, "
795 "notify=%p, url=%s, buf=%s\n",
796 (void*)npp, target, len, file, notifyData, relativeURL,
797 buf));
799 PluginDestructionGuard guard(npp);
801 return MakeNewNPAPIStreamInternal(npp, relativeURL, target,
802 eNPPStreamTypeInternal_Post, PR_TRUE,
803 notifyData, len, buf, file);
806 NPError NP_CALLBACK
807 _posturl(NPP npp, const char *relativeURL, const char *target,
808 uint32_t len, const char *buf, NPBool file)
810 if (!NS_IsMainThread()) {
811 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_posturl called from the wrong thread\n"));
812 return NPERR_INVALID_PARAM;
814 NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
815 ("NPN_PostURL: npp=%p, target=%s, file=%d, len=%d, url=%s, "
816 "buf=%s\n",
817 (void*)npp, target, file, len, relativeURL, buf));
819 PluginDestructionGuard guard(npp);
821 return MakeNewNPAPIStreamInternal(npp, relativeURL, target,
822 eNPPStreamTypeInternal_Post, PR_FALSE, nsnull,
823 len, buf, file);
826 // A little helper class used to wrap up plugin manager streams (that is,
827 // streams from the plugin to the browser).
828 class nsNPAPIStreamWrapper : nsISupports
830 public:
831 NS_DECL_ISUPPORTS
833 protected:
834 nsIOutputStream *fStream;
835 NPStream fNPStream;
837 public:
838 nsNPAPIStreamWrapper(nsIOutputStream* stream);
839 ~nsNPAPIStreamWrapper();
841 void GetStream(nsIOutputStream* &result);
842 NPStream* GetNPStream(void) { return &fNPStream; }
845 NS_IMPL_ISUPPORTS1(nsNPAPIStreamWrapper, nsISupports)
847 nsNPAPIStreamWrapper::nsNPAPIStreamWrapper(nsIOutputStream* stream)
848 : fStream(stream)
850 NS_ASSERTION(stream, "bad stream");
852 fStream = stream;
853 NS_ADDREF(fStream);
855 memset(&fNPStream, 0, sizeof(fNPStream));
856 fNPStream.ndata = (void*) this;
859 nsNPAPIStreamWrapper::~nsNPAPIStreamWrapper(void)
861 fStream->Close();
862 NS_IF_RELEASE(fStream);
865 void
866 nsNPAPIStreamWrapper::GetStream(nsIOutputStream* &result)
868 result = fStream;
869 NS_IF_ADDREF(fStream);
872 NPError NP_CALLBACK
873 _newstream(NPP npp, NPMIMEType type, const char* target, NPStream* *result)
875 if (!NS_IsMainThread()) {
876 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_newstream called from the wrong thread\n"));
877 return NPERR_INVALID_PARAM;
879 NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
880 ("NPN_NewStream: npp=%p, type=%s, target=%s\n", (void*)npp,
881 (const char *)type, target));
883 NPError err = NPERR_INVALID_INSTANCE_ERROR;
884 if (npp && npp->ndata) {
885 nsIPluginInstance *inst = (nsIPluginInstance *) npp->ndata;
887 PluginDestructionGuard guard(inst);
889 nsCOMPtr<nsIOutputStream> stream;
890 nsCOMPtr<nsIPluginInstancePeer> peer;
891 if (NS_SUCCEEDED(inst->GetPeer(getter_AddRefs(peer))) &&
892 peer &&
893 NS_SUCCEEDED(peer->NewStream((const char*) type, target,
894 getter_AddRefs(stream)))) {
895 nsNPAPIStreamWrapper* wrapper = new nsNPAPIStreamWrapper(stream);
896 if (wrapper) {
897 (*result) = wrapper->GetNPStream();
898 err = NPERR_NO_ERROR;
899 } else {
900 err = NPERR_OUT_OF_MEMORY_ERROR;
902 } else {
903 err = NPERR_GENERIC_ERROR;
906 return err;
909 int32_t NP_CALLBACK
910 _write(NPP npp, NPStream *pstream, int32_t len, void *buffer)
912 if (!NS_IsMainThread()) {
913 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_write called from the wrong thread\n"));
914 return 0;
916 NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
917 ("NPN_Write: npp=%p, url=%s, len=%d, buffer=%s\n", (void*)npp,
918 pstream->url, len, (char*)buffer));
920 // negative return indicates failure to the plugin
921 if (!npp)
922 return -1;
924 PluginDestructionGuard guard(npp);
926 nsNPAPIStreamWrapper* wrapper = (nsNPAPIStreamWrapper*) pstream->ndata;
927 NS_ASSERTION(wrapper, "null stream");
928 if (!wrapper)
929 return -1;
931 nsIOutputStream* stream;
932 wrapper->GetStream(stream);
934 PRUint32 count = 0;
935 nsresult rv = stream->Write((char *)buffer, len, &count);
936 NS_RELEASE(stream);
938 if (rv != NS_OK)
939 return -1;
941 return (int32_t)count;
944 NPError NP_CALLBACK
945 _destroystream(NPP npp, NPStream *pstream, NPError reason)
947 if (!NS_IsMainThread()) {
948 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_write called from the wrong thread\n"));
949 return NPERR_INVALID_PARAM;
951 NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
952 ("NPN_DestroyStream: npp=%p, url=%s, reason=%d\n", (void*)npp,
953 pstream->url, (int)reason));
955 if (!npp)
956 return NPERR_INVALID_INSTANCE_ERROR;
958 PluginDestructionGuard guard(npp);
960 nsCOMPtr<nsIPluginStreamListener> listener =
961 do_QueryInterface((nsISupports *)pstream->ndata);
963 // DestroyStream can kill two kinds of streams: NPP derived and NPN derived.
964 // check to see if they're trying to kill a NPP stream
965 if (listener) {
966 // Tell the stream listner that the stream is now gone.
967 listener->OnStopBinding(nsnull, NS_BINDING_ABORTED);
969 // FIXME: http://bugzilla.mozilla.org/show_bug.cgi?id=240131
971 // Is it ok to leave pstream->ndata set here, and who releases it
972 // (or is it even properly ref counted)? And who closes the stream
973 // etc?
974 } else {
975 nsNPAPIStreamWrapper* wrapper = (nsNPAPIStreamWrapper *)pstream->ndata;
976 NS_ASSERTION(wrapper, "null wrapper");
978 if (!wrapper)
979 return NPERR_INVALID_PARAM;
981 // This will release the wrapped nsIOutputStream.
982 delete wrapper;
983 pstream->ndata = nsnull;
986 return NPERR_NO_ERROR;
989 void NP_CALLBACK
990 _status(NPP npp, const char *message)
992 if (!NS_IsMainThread()) {
993 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_status called from the wrong thread\n"));
994 return;
996 NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_Status: npp=%p, message=%s\n",
997 (void*)npp, message));
999 if (!npp || !npp->ndata) {
1000 NS_WARNING("_status: npp or npp->ndata == 0");
1001 return;
1004 nsIPluginInstance *inst = (nsIPluginInstance *) npp->ndata;
1006 PluginDestructionGuard guard(inst);
1008 nsCOMPtr<nsIPluginInstancePeer> peer;
1009 if (NS_SUCCEEDED(inst->GetPeer(getter_AddRefs(peer))) && peer) {
1010 peer->ShowStatus(message);
1014 void NP_CALLBACK
1015 _memfree (void *ptr)
1017 if (!NS_IsMainThread()) {
1018 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_memfree called from the wrong thread\n"));
1020 NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_MemFree: ptr=%p\n", ptr));
1022 if (ptr)
1023 nsMemory::Free(ptr);
1026 uint32_t NP_CALLBACK
1027 _memflush(uint32_t size)
1029 if (!NS_IsMainThread()) {
1030 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_memflush called from the wrong thread\n"));
1032 NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_MemFlush: size=%d\n", size));
1034 nsMemory::HeapMinimize(PR_TRUE);
1035 return 0;
1038 void NP_CALLBACK
1039 _reloadplugins(NPBool reloadPages)
1041 if (!NS_IsMainThread()) {
1042 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_reloadplugins called from the wrong thread\n"));
1043 return;
1045 NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
1046 ("NPN_ReloadPlugins: reloadPages=%d\n", reloadPages));
1048 nsCOMPtr<nsIPluginManager> pm(do_GetService(kPluginManagerCID));
1049 if (!pm)
1050 return;
1052 pm->ReloadPlugins(reloadPages);
1055 void NP_CALLBACK
1056 _invalidaterect(NPP npp, NPRect *invalidRect)
1058 if (!NS_IsMainThread()) {
1059 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_invalidaterect called from the wrong thread\n"));
1060 return;
1062 NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
1063 ("NPN_InvalidateRect: npp=%p, top=%d, left=%d, bottom=%d, "
1064 "right=%d\n", (void *)npp, invalidRect->top,
1065 invalidRect->left, invalidRect->bottom, invalidRect->right));
1067 if (!npp || !npp->ndata) {
1068 NS_WARNING("_invalidaterect: npp or npp->ndata == 0");
1069 return;
1072 nsIPluginInstance *inst = (nsIPluginInstance *) npp->ndata;
1074 PluginDestructionGuard guard(inst);
1076 nsCOMPtr<nsIPluginInstancePeer> peer;
1077 if (NS_SUCCEEDED(inst->GetPeer(getter_AddRefs(peer))) && peer) {
1078 nsCOMPtr<nsIWindowlessPluginInstancePeer> wpeer(do_QueryInterface(peer));
1079 if (wpeer) {
1080 // XXX nsRect & NPRect are structurally equivalent
1081 wpeer->InvalidateRect((nsPluginRect *)invalidRect);
1086 void NP_CALLBACK
1087 _invalidateregion(NPP npp, NPRegion invalidRegion)
1089 if (!NS_IsMainThread()) {
1090 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_invalidateregion called from the wrong thread\n"));
1091 return;
1093 NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
1094 ("NPN_InvalidateRegion: npp=%p, region=%p\n", (void*)npp,
1095 (void*)invalidRegion));
1097 if (!npp || !npp->ndata) {
1098 NS_WARNING("_invalidateregion: npp or npp->ndata == 0");
1099 return;
1102 nsIPluginInstance *inst = (nsIPluginInstance *)npp->ndata;
1104 PluginDestructionGuard guard(inst);
1106 nsCOMPtr<nsIPluginInstancePeer> peer;
1107 if (NS_SUCCEEDED(inst->GetPeer(getter_AddRefs(peer))) && peer) {
1108 nsCOMPtr<nsIWindowlessPluginInstancePeer> wpeer(do_QueryInterface(peer));
1109 if (wpeer) {
1110 // nsPluginRegion & NPRegion are typedef'd to the same thing
1111 wpeer->InvalidateRegion((nsPluginRegion)invalidRegion);
1116 void NP_CALLBACK
1117 _forceredraw(NPP npp)
1119 if (!NS_IsMainThread()) {
1120 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_forceredraw called from the wrong thread\n"));
1121 return;
1123 NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_ForceDraw: npp=%p\n", (void*)npp));
1125 if (!npp || !npp->ndata) {
1126 NS_WARNING("_forceredraw: npp or npp->ndata == 0");
1127 return;
1130 nsIPluginInstance *inst = (nsIPluginInstance *) npp->ndata;
1132 PluginDestructionGuard guard(inst);
1134 nsCOMPtr<nsIPluginInstancePeer> peer;
1135 if (NS_SUCCEEDED(inst->GetPeer(getter_AddRefs(peer))) && peer) {
1136 nsCOMPtr<nsIWindowlessPluginInstancePeer> wpeer(do_QueryInterface(peer));
1137 if (wpeer) {
1138 wpeer->ForceRedraw();
1143 static nsIDocument *
1144 GetDocumentFromNPP(NPP npp)
1146 NS_ENSURE_TRUE(npp, nsnull);
1148 nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)npp->ndata;
1149 NS_ENSURE_TRUE(inst, nsnull);
1151 PluginDestructionGuard guard(inst);
1153 nsCOMPtr<nsIPluginInstancePeer> pip;
1154 inst->GetPeer(getter_AddRefs(pip));
1155 nsCOMPtr<nsPIPluginInstancePeer> pp(do_QueryInterface(pip));
1156 NS_ENSURE_TRUE(pp, nsnull);
1158 nsCOMPtr<nsIPluginInstanceOwner> owner;
1159 pp->GetOwner(getter_AddRefs(owner));
1160 NS_ENSURE_TRUE(owner, nsnull);
1162 nsCOMPtr<nsIDocument> doc;
1163 owner->GetDocument(getter_AddRefs(doc));
1165 return doc;
1168 static JSContext *
1169 GetJSContextFromDoc(nsIDocument *doc)
1171 nsIScriptGlobalObject *sgo = doc->GetScriptGlobalObject();
1172 NS_ENSURE_TRUE(sgo, nsnull);
1174 nsIScriptContext *scx = sgo->GetContext();
1175 NS_ENSURE_TRUE(scx, nsnull);
1177 return (JSContext *)scx->GetNativeContext();
1180 static JSContext *
1181 GetJSContextFromNPP(NPP npp)
1183 nsIDocument *doc = GetDocumentFromNPP(npp);
1184 NS_ENSURE_TRUE(doc, nsnull);
1186 return GetJSContextFromDoc(doc);
1189 NPObject* NP_CALLBACK
1190 _getwindowobject(NPP npp)
1192 if (!NS_IsMainThread()) {
1193 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getwindowobject called from the wrong thread\n"));
1194 return nsnull;
1196 JSContext *cx = GetJSContextFromNPP(npp);
1197 NS_ENSURE_TRUE(cx, nsnull);
1199 // Using ::JS_GetGlobalObject(cx) is ok here since the window we
1200 // want to return here is the outer window, *not* the inner (since
1201 // we don't know what the plugin will do with it).
1202 return nsJSObjWrapper::GetNewOrUsed(npp, cx, ::JS_GetGlobalObject(cx));
1205 NPObject* NP_CALLBACK
1206 _getpluginelement(NPP npp)
1208 if (!NS_IsMainThread()) {
1209 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getpluginelement called from the wrong thread\n"));
1210 return nsnull;
1212 nsIDOMElement *elementp = nsnull;
1213 NPError nperr = _getvalue(npp, NPNVDOMElement, &elementp);
1215 if (nperr != NPERR_NO_ERROR) {
1216 return nsnull;
1219 // Pass ownership of elementp to element
1220 nsCOMPtr<nsIDOMElement> element;
1221 element.swap(elementp);
1223 JSContext *cx = GetJSContextFromNPP(npp);
1224 NS_ENSURE_TRUE(cx, nsnull);
1226 nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID()));
1227 NS_ENSURE_TRUE(xpc, nsnull);
1229 nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
1230 xpc->WrapNative(cx, ::JS_GetGlobalObject(cx), element,
1231 NS_GET_IID(nsIDOMElement),
1232 getter_AddRefs(holder));
1233 NS_ENSURE_TRUE(holder, nsnull);
1235 JSObject* obj = nsnull;
1236 holder->GetJSObject(&obj);
1237 NS_ENSURE_TRUE(obj, nsnull);
1239 return nsJSObjWrapper::GetNewOrUsed(npp, cx, obj);
1242 static NPIdentifier
1243 doGetIdentifier(JSContext *cx, const NPUTF8* name)
1245 NS_ConvertUTF8toUTF16 utf16name(name);
1247 JSString *str = ::JS_InternUCStringN(cx, (jschar *)utf16name.get(),
1248 utf16name.Length());
1250 if (!str)
1251 return NULL;
1253 return (NPIdentifier)STRING_TO_JSVAL(str);
1256 NPIdentifier NP_CALLBACK
1257 _getstringidentifier(const NPUTF8* name)
1259 if (!name) {
1260 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_getstringidentifier: passed null name"));
1261 return NULL;
1263 if (!NS_IsMainThread()) {
1264 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getstringidentifier called from the wrong thread\n"));
1267 nsCOMPtr<nsIThreadJSContextStack> stack =
1268 do_GetService("@mozilla.org/js/xpc/ContextStack;1");
1269 if (!stack)
1270 return NULL;
1272 JSContext *cx = nsnull;
1273 stack->GetSafeJSContext(&cx);
1274 if (!cx)
1275 return NULL;
1277 JSAutoRequest ar(cx);
1278 return doGetIdentifier(cx, name);
1281 void NP_CALLBACK
1282 _getstringidentifiers(const NPUTF8** names, int32_t nameCount,
1283 NPIdentifier *identifiers)
1285 if (!NS_IsMainThread()) {
1286 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getstringidentifiers called from the wrong thread\n"));
1288 nsCOMPtr<nsIThreadJSContextStack> stack =
1289 do_GetService("@mozilla.org/js/xpc/ContextStack;1");
1290 if (!stack)
1291 return;
1293 JSContext *cx = nsnull;
1294 stack->GetSafeJSContext(&cx);
1295 if (!cx)
1296 return;
1298 JSAutoRequest ar(cx);
1300 for (int32_t i = 0; i < nameCount; ++i) {
1301 if (names[i]) {
1302 identifiers[i] = doGetIdentifier(cx, names[i]);
1303 } else {
1304 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_getstringidentifiers: passed null name"));
1305 identifiers[i] = NULL;
1310 NPIdentifier NP_CALLBACK
1311 _getintidentifier(int32_t intid)
1313 if (!NS_IsMainThread()) {
1314 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getstringidentifier called from the wrong thread\n"));
1316 return (NPIdentifier)INT_TO_JSVAL(intid);
1319 NPUTF8* NP_CALLBACK
1320 _utf8fromidentifier(NPIdentifier identifier)
1322 if (!NS_IsMainThread()) {
1323 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_utf8fromidentifier called from the wrong thread\n"));
1325 if (!identifier)
1326 return NULL;
1328 jsval v = (jsval)identifier;
1330 if (!JSVAL_IS_STRING(v)) {
1331 return nsnull;
1334 JSString *str = JSVAL_TO_STRING(v);
1336 return
1337 ToNewUTF8String(nsDependentString((PRUnichar *)::JS_GetStringChars(str),
1338 ::JS_GetStringLength(str)));
1341 int32_t NP_CALLBACK
1342 _intfromidentifier(NPIdentifier identifier)
1344 if (!NS_IsMainThread()) {
1345 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_intfromidentifier called from the wrong thread\n"));
1347 jsval v = (jsval)identifier;
1349 if (!JSVAL_IS_INT(v)) {
1350 return PR_INT32_MIN;
1353 return JSVAL_TO_INT(v);
1356 bool NP_CALLBACK
1357 _identifierisstring(NPIdentifier identifier)
1359 if (!NS_IsMainThread()) {
1360 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_identifierisstring called from the wrong thread\n"));
1362 jsval v = (jsval)identifier;
1364 return JSVAL_IS_STRING(v);
1367 NPObject* NP_CALLBACK
1368 _createobject(NPP npp, NPClass* aClass)
1370 if (!NS_IsMainThread()) {
1371 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_createobject called from the wrong thread\n"));
1372 return nsnull;
1374 if (!npp) {
1375 NS_ERROR("Null npp passed to _createobject()!");
1377 return nsnull;
1380 PluginDestructionGuard guard(npp);
1382 if (!aClass) {
1383 NS_ERROR("Null class passed to _createobject()!");
1385 return nsnull;
1388 NPPAutoPusher nppPusher(npp);
1390 NPObject *npobj;
1392 if (aClass->allocate) {
1393 npobj = aClass->allocate(npp, aClass);
1394 } else {
1395 npobj = (NPObject *)PR_Malloc(sizeof(NPObject));
1398 if (npobj) {
1399 npobj->_class = aClass;
1400 npobj->referenceCount = 1;
1403 NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
1404 ("Created NPObject %p, NPClass %p\n", npobj, aClass));
1406 return npobj;
1409 NPObject* NP_CALLBACK
1410 _retainobject(NPObject* npobj)
1412 if (!NS_IsMainThread()) {
1413 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_retainobject called from the wrong thread\n"));
1415 if (npobj) {
1416 PR_AtomicIncrement((PRInt32*)&npobj->referenceCount);
1419 return npobj;
1422 void NP_CALLBACK
1423 _releaseobject(NPObject* npobj)
1425 if (!NS_IsMainThread()) {
1426 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_releaseobject called from the wrong thread\n"));
1428 if (!npobj)
1429 return;
1431 int32_t refCnt = PR_AtomicDecrement((PRInt32*)&npobj->referenceCount);
1433 if (refCnt == 0) {
1434 nsNPObjWrapper::OnDestroy(npobj);
1436 NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
1437 ("Deleting NPObject %p, refcount hit 0\n", npobj));
1439 if (npobj->_class && npobj->_class->deallocate) {
1440 npobj->_class->deallocate(npobj);
1441 } else {
1442 PR_Free(npobj);
1447 bool NP_CALLBACK
1448 _invoke(NPP npp, NPObject* npobj, NPIdentifier method, const NPVariant *args,
1449 uint32_t argCount, NPVariant *result)
1451 if (!NS_IsMainThread()) {
1452 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_invoke called from the wrong thread\n"));
1453 return false;
1455 if (!npp || !npobj || !npobj->_class || !npobj->_class->invoke)
1456 return false;
1458 PluginDestructionGuard guard(npp);
1460 NPPExceptionAutoHolder nppExceptionHolder;
1461 NPPAutoPusher nppPusher(npp);
1463 NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
1464 ("NPN_Invoke(npp %p, npobj %p, method %p, args %d\n", npp,
1465 npobj, method, argCount));
1467 return npobj->_class->invoke(npobj, method, args, argCount, result);
1470 bool NP_CALLBACK
1471 _invokeDefault(NPP npp, NPObject* npobj, const NPVariant *args,
1472 uint32_t argCount, NPVariant *result)
1474 if (!NS_IsMainThread()) {
1475 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_invokedefault called from the wrong thread\n"));
1476 return false;
1478 if (!npp || !npobj || !npobj->_class || !npobj->_class->invokeDefault)
1479 return false;
1481 NPPExceptionAutoHolder nppExceptionHolder;
1482 NPPAutoPusher nppPusher(npp);
1484 NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
1485 ("NPN_InvokeDefault(npp %p, npobj %p, args %d\n", npp,
1486 npobj, argCount));
1488 return npobj->_class->invokeDefault(npobj, args, argCount, result);
1491 bool NP_CALLBACK
1492 _evaluate(NPP npp, NPObject* npobj, NPString *script, NPVariant *result)
1494 if (!NS_IsMainThread()) {
1495 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_evaluate called from the wrong thread\n"));
1496 return false;
1498 if (!npp)
1499 return false;
1501 NPPAutoPusher nppPusher(npp);
1503 nsIDocument *doc = GetDocumentFromNPP(npp);
1504 NS_ENSURE_TRUE(doc, false);
1506 JSContext *cx = GetJSContextFromDoc(doc);
1507 NS_ENSURE_TRUE(cx, false);
1509 JSObject *obj =
1510 nsNPObjWrapper::GetNewOrUsed(npp, cx, npobj);
1512 if (!obj) {
1513 return false;
1516 // Root obj and the rval (below).
1517 jsval vec[] = { OBJECT_TO_JSVAL(obj), JSVAL_NULL };
1518 JSAutoTempValueRooter tvr(cx, NS_ARRAY_LENGTH(vec), vec);
1519 jsval *rval = &vec[1];
1521 if (result) {
1522 // Initialize the out param to void
1523 VOID_TO_NPVARIANT(*result);
1526 if (!script || !script->UTF8Length || !script->UTF8Characters) {
1527 // Nothing to evaluate.
1529 return true;
1532 NS_ConvertUTF8toUTF16 utf16script(script->UTF8Characters,
1533 script->UTF8Length);
1535 nsCOMPtr<nsIScriptContext> scx = GetScriptContextFromJSContext(cx);
1536 NS_ENSURE_TRUE(scx, false);
1538 nsIPrincipal *principal = doc->NodePrincipal();
1540 nsCAutoString specStr;
1541 const char *spec;
1543 nsCOMPtr<nsIURI> uri;
1544 principal->GetURI(getter_AddRefs(uri));
1546 if (uri) {
1547 uri->GetSpec(specStr);
1548 spec = specStr.get();
1549 } else {
1550 // No URI in a principal means it's the system principal. If the
1551 // document URI is a chrome:// URI, pass that in as the URI of the
1552 // script, else pass in null for the filename as there's no way to
1553 // know where this document really came from. Passing in null here
1554 // also means that the script gets treated by XPConnect as if it
1555 // needs additional protection, which is what we want for unknown
1556 // chrome code anyways.
1558 uri = doc->GetDocumentURI();
1559 PRBool isChrome = PR_FALSE;
1561 if (uri && NS_SUCCEEDED(uri->SchemeIs("chrome", &isChrome)) && isChrome) {
1562 uri->GetSpec(specStr);
1563 spec = specStr.get();
1564 } else {
1565 spec = nsnull;
1569 NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
1570 ("NPN_Evaluate(npp %p, npobj %p, script <<<%s>>>) called\n",
1571 npp, npobj, script->UTF8Characters));
1573 nsresult rv = scx->EvaluateStringWithValue(utf16script, obj, principal,
1574 spec, 0, 0, rval, nsnull);
1576 return NS_SUCCEEDED(rv) &&
1577 (!result || JSValToNPVariant(npp, cx, *rval, result));
1580 bool NP_CALLBACK
1581 _getproperty(NPP npp, NPObject* npobj, NPIdentifier property,
1582 NPVariant *result)
1584 if (!NS_IsMainThread()) {
1585 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getproperty called from the wrong thread\n"));
1586 return false;
1588 if (!npp || !npobj || !npobj->_class || !npobj->_class->getProperty)
1589 return false;
1591 NPPExceptionAutoHolder nppExceptionHolder;
1592 NPPAutoPusher nppPusher(npp);
1594 NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
1595 ("NPN_GetProperty(npp %p, npobj %p, property %p) called\n",
1596 npp, npobj, property));
1598 return npobj->_class->getProperty(npobj, property, result);
1601 bool NP_CALLBACK
1602 _setproperty(NPP npp, NPObject* npobj, NPIdentifier property,
1603 const NPVariant *value)
1605 if (!NS_IsMainThread()) {
1606 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_setproperty called from the wrong thread\n"));
1607 return false;
1609 if (!npp || !npobj || !npobj->_class || !npobj->_class->setProperty)
1610 return false;
1612 NPPExceptionAutoHolder nppExceptionHolder;
1613 NPPAutoPusher nppPusher(npp);
1615 NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
1616 ("NPN_SetProperty(npp %p, npobj %p, property %p) called\n",
1617 npp, npobj, property));
1619 return npobj->_class->setProperty(npobj, property, value);
1622 bool NP_CALLBACK
1623 _removeproperty(NPP npp, NPObject* npobj, NPIdentifier property)
1625 if (!NS_IsMainThread()) {
1626 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_removeproperty called from the wrong thread\n"));
1627 return false;
1629 if (!npp || !npobj || !npobj->_class || !npobj->_class->removeProperty)
1630 return false;
1632 NPPExceptionAutoHolder nppExceptionHolder;
1633 NPPAutoPusher nppPusher(npp);
1635 NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
1636 ("NPN_RemoveProperty(npp %p, npobj %p, property %p) called\n",
1637 npp, npobj, property));
1639 return npobj->_class->removeProperty(npobj, property);
1642 bool NP_CALLBACK
1643 _hasproperty(NPP npp, NPObject* npobj, NPIdentifier propertyName)
1645 if (!NS_IsMainThread()) {
1646 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_hasproperty called from the wrong thread\n"));
1647 return false;
1649 if (!npp || !npobj || !npobj->_class || !npobj->_class->hasProperty)
1650 return false;
1652 NPPExceptionAutoHolder nppExceptionHolder;
1653 NPPAutoPusher nppPusher(npp);
1655 NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
1656 ("NPN_HasProperty(npp %p, npobj %p, property %p) called\n",
1657 npp, npobj, propertyName));
1659 return npobj->_class->hasProperty(npobj, propertyName);
1662 bool NP_CALLBACK
1663 _hasmethod(NPP npp, NPObject* npobj, NPIdentifier methodName)
1665 if (!NS_IsMainThread()) {
1666 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_hasmethod called from the wrong thread\n"));
1667 return false;
1669 if (!npp || !npobj || !npobj->_class || !npobj->_class->hasMethod)
1670 return false;
1672 NPPExceptionAutoHolder nppExceptionHolder;
1673 NPPAutoPusher nppPusher(npp);
1675 NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
1676 ("NPN_HasMethod(npp %p, npobj %p, property %p) called\n",
1677 npp, npobj, methodName));
1679 return npobj->_class->hasProperty(npobj, methodName);
1682 bool NP_CALLBACK
1683 _enumerate(NPP npp, NPObject *npobj, NPIdentifier **identifier,
1684 uint32_t *count)
1686 if (!NS_IsMainThread()) {
1687 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_enumerate called from the wrong thread\n"));
1688 return false;
1690 if (!npp || !npobj || !npobj->_class)
1691 return false;
1693 NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
1694 ("NPN_Enumerate(npp %p, npobj %p) called\n", npp, npobj));
1696 if (!NP_CLASS_STRUCT_VERSION_HAS_ENUM(npobj->_class) ||
1697 !npobj->_class->enumerate) {
1698 *identifier = 0;
1699 *count = 0;
1700 return true;
1703 NPPExceptionAutoHolder nppExceptionHolder;
1704 NPPAutoPusher nppPusher(npp);
1706 return npobj->_class->enumerate(npobj, identifier, count);
1709 bool NP_CALLBACK
1710 _construct(NPP npp, NPObject* npobj, const NPVariant *args,
1711 uint32_t argCount, NPVariant *result)
1713 if (!NS_IsMainThread()) {
1714 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_construct called from the wrong thread\n"));
1715 return false;
1717 if (!npp || !npobj || !npobj->_class ||
1718 !NP_CLASS_STRUCT_VERSION_HAS_CTOR(npobj->_class) ||
1719 !npobj->_class->construct) {
1720 return false;
1723 NPPExceptionAutoHolder nppExceptionHolder;
1724 NPPAutoPusher nppPusher(npp);
1726 return npobj->_class->construct(npobj, args, argCount, result);
1729 #ifdef MOZ_MEMORY_WINDOWS
1730 extern "C" size_t malloc_usable_size(const void *ptr);
1732 BOOL
1733 InHeap(HANDLE hHeap, LPVOID lpMem)
1735 BOOL success = FALSE;
1736 PROCESS_HEAP_ENTRY he;
1737 he.lpData = NULL;
1738 while (HeapWalk(hHeap, &he) != 0) {
1739 if (he.lpData == lpMem) {
1740 success = TRUE;
1741 break;
1744 HeapUnlock(hHeap);
1745 return success;
1747 #endif
1749 void NP_CALLBACK
1750 _releasevariantvalue(NPVariant* variant)
1752 if (!NS_IsMainThread()) {
1753 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_releasevariantvalue called from the wrong thread\n"));
1755 switch (variant->type) {
1756 case NPVariantType_Void :
1757 case NPVariantType_Null :
1758 case NPVariantType_Bool :
1759 case NPVariantType_Int32 :
1760 case NPVariantType_Double :
1761 break;
1762 case NPVariantType_String :
1764 const NPString *s = &NPVARIANT_TO_STRING(*variant);
1766 if (s->UTF8Characters) {
1767 #ifdef MOZ_MEMORY_WINDOWS
1768 if (malloc_usable_size((void *)s->UTF8Characters) != 0) {
1769 PR_Free((void *)s->UTF8Characters);
1770 } else {
1771 void *p = (void *)s->UTF8Characters;
1772 DWORD nheaps = 0;
1773 nsAutoTArray<HANDLE, 50> heaps;
1774 nheaps = GetProcessHeaps(0, heaps.Elements());
1775 heaps.AppendElements(nheaps);
1776 GetProcessHeaps(nheaps, heaps.Elements());
1777 for (DWORD i = 0; i < nheaps; i++) {
1778 if (InHeap(heaps[i], p)) {
1779 HeapFree(heaps[i], 0, p);
1780 break;
1784 #else
1785 PR_Free((void *)s->UTF8Characters);
1786 #endif
1788 break;
1790 case NPVariantType_Object:
1792 NPObject *npobj = NPVARIANT_TO_OBJECT(*variant);
1794 if (npobj)
1795 _releaseobject(npobj);
1797 break;
1799 default:
1800 NS_ERROR("Unknown NPVariant type!");
1803 VOID_TO_NPVARIANT(*variant);
1806 bool NP_CALLBACK
1807 _tostring(NPObject* npobj, NPVariant *result)
1809 NS_ERROR("Write me!");
1811 if (!NS_IsMainThread()) {
1812 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_tostring called from the wrong thread\n"));
1813 return false;
1816 return false;
1819 static char *gNPPException;
1821 void NP_CALLBACK
1822 _setexception(NPObject* npobj, const NPUTF8 *message)
1824 if (!NS_IsMainThread()) {
1825 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_setexception called from the wrong thread\n"));
1826 return;
1829 if (gNPPException) {
1830 // If a plugin throws multiple exceptions, we'll only report the
1831 // last one for now.
1832 free(gNPPException);
1835 gNPPException = strdup(message);
1838 const char *
1839 PeekException()
1841 return gNPPException;
1844 void
1845 PopException()
1847 NS_ASSERTION(gNPPException, "Uh, no NPP exception to pop!");
1849 if (gNPPException) {
1850 free(gNPPException);
1852 gNPPException = nsnull;
1856 NPPExceptionAutoHolder::NPPExceptionAutoHolder()
1857 : mOldException(gNPPException)
1859 gNPPException = nsnull;
1862 NPPExceptionAutoHolder::~NPPExceptionAutoHolder()
1864 NS_ASSERTION(!gNPPException, "NPP exception not properly cleared!");
1866 gNPPException = mOldException;
1869 NPError NP_CALLBACK
1870 _getvalue(NPP npp, NPNVariable variable, void *result)
1872 if (!NS_IsMainThread()) {
1873 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getvalue called from the wrong thread\n"));
1874 return NPERR_INVALID_PARAM;
1876 NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetValue: npp=%p, var=%d\n",
1877 (void*)npp, (int)variable));
1879 nsresult res;
1881 PluginDestructionGuard guard(npp);
1883 switch(variable) {
1884 #if defined(XP_UNIX) && !defined(XP_MACOSX)
1885 case NPNVxDisplay : {
1886 #ifdef MOZ_WIDGET_GTK2
1887 if (npp) {
1888 nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) npp->ndata;
1889 PRBool windowless = PR_FALSE;
1890 inst->GetValue(nsPluginInstanceVariable_WindowlessBool, &windowless);
1891 NPBool needXEmbed = PR_FALSE;
1892 if (!windowless) {
1893 inst->GetValue((nsPluginInstanceVariable)NPPVpluginNeedsXEmbed, &needXEmbed);
1895 if (windowless || needXEmbed) {
1896 (*(Display **)result) = GDK_DISPLAY();
1897 return NPERR_NO_ERROR;
1900 // adobe nppdf calls XtGetApplicationNameAndClass(display,
1901 // &instance, &class) we have to init Xt toolkit before get
1902 // XtDisplay just call gtk_xtbin_new(w,0) once
1903 static GtkWidget *gtkXtBinHolder = 0;
1904 if (!gtkXtBinHolder) {
1905 gtkXtBinHolder = gtk_xtbin_new(GDK_ROOT_PARENT(),0);
1906 // it crashes on destroy, let it leak
1907 // gtk_widget_destroy(gtkXtBinHolder);
1909 (*(Display **)result) = GTK_XTBIN(gtkXtBinHolder)->xtdisplay;
1910 return NPERR_NO_ERROR;
1911 #endif
1912 return NPERR_GENERIC_ERROR;
1915 case NPNVxtAppContext:
1916 return NPERR_GENERIC_ERROR;
1917 #endif
1919 #if defined(XP_WIN) || defined(XP_OS2) || defined(MOZ_WIDGET_GTK2)
1920 case NPNVnetscapeWindow: {
1921 if (!npp || !npp->ndata)
1922 return NPERR_INVALID_INSTANCE_ERROR;
1924 nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) npp->ndata;
1926 nsCOMPtr<nsIPluginInstancePeer> peer;
1927 if (NS_SUCCEEDED(inst->GetPeer(getter_AddRefs(peer))) &&
1928 peer &&
1929 NS_SUCCEEDED(peer->GetValue(nsPluginInstancePeerVariable_NetscapeWindow,
1930 result))) {
1931 return NPERR_NO_ERROR;
1933 return NPERR_GENERIC_ERROR;
1935 #endif
1937 case NPNVjavascriptEnabledBool: {
1938 *(NPBool*)result = PR_FALSE;
1939 nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
1940 if (prefs) {
1941 PRBool js = PR_FALSE;;
1942 res = prefs->GetBoolPref("javascript.enabled", &js);
1943 if (NS_SUCCEEDED(res))
1944 *(NPBool*)result = js;
1946 return NPERR_NO_ERROR;
1949 case NPNVasdEnabledBool:
1950 *(NPBool*)result = PR_FALSE;
1951 return NPERR_NO_ERROR;
1953 case NPNVisOfflineBool: {
1954 PRBool offline = PR_FALSE;
1955 nsCOMPtr<nsIIOService> ioservice =
1956 do_GetService(NS_IOSERVICE_CONTRACTID, &res);
1957 if (NS_SUCCEEDED(res))
1958 res = ioservice->GetOffline(&offline);
1959 if (NS_FAILED(res))
1960 return NPERR_GENERIC_ERROR;
1962 *(NPBool*)result = offline;
1963 return NPERR_NO_ERROR;
1966 case NPNVserviceManager: {
1967 nsIServiceManager * sm;
1968 res = NS_GetServiceManager(&sm);
1969 if (NS_SUCCEEDED(res)) {
1970 *(nsIServiceManager**)result = sm;
1971 return NPERR_NO_ERROR;
1972 } else {
1973 return NPERR_GENERIC_ERROR;
1977 case NPNVDOMElement: {
1978 nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) npp->ndata;
1979 NS_ENSURE_TRUE(inst, NPERR_GENERIC_ERROR);
1981 nsCOMPtr<nsIPluginInstancePeer> pip;
1982 inst->GetPeer(getter_AddRefs(pip));
1983 nsCOMPtr<nsIPluginTagInfo2> pti2 (do_QueryInterface(pip));
1984 if (pti2) {
1985 nsCOMPtr<nsIDOMElement> e;
1986 pti2->GetDOMElement(getter_AddRefs(e));
1987 if (e) {
1988 NS_ADDREF(*(nsIDOMElement**)result = e.get());
1989 return NPERR_NO_ERROR;
1992 return NPERR_GENERIC_ERROR;
1995 case NPNVDOMWindow: {
1996 nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)npp->ndata;
1997 NS_ENSURE_TRUE(inst, NPERR_GENERIC_ERROR);
1999 nsIDOMWindow *domWindow = inst->GetDOMWindow().get();
2001 if (domWindow) {
2002 // Pass over ownership of domWindow to the caller.
2003 (*(nsIDOMWindow**)result) = domWindow;
2005 return NPERR_NO_ERROR;
2007 return NPERR_GENERIC_ERROR;
2010 case NPNVToolkit: {
2011 #ifdef MOZ_WIDGET_GTK2
2012 *((NPNToolkitType*)result) = NPNVGtk2;
2013 #endif
2015 if (*(NPNToolkitType*)result)
2016 return NPERR_NO_ERROR;
2018 return NPERR_GENERIC_ERROR;
2021 case NPNVSupportsXEmbedBool: {
2022 #ifdef MOZ_WIDGET_GTK2
2023 *(NPBool*)result = PR_TRUE;
2024 #else
2025 *(NPBool*)result = PR_FALSE;
2026 #endif
2027 return NPERR_NO_ERROR;
2030 case NPNVWindowNPObject: {
2031 *(NPObject **)result = _getwindowobject(npp);
2033 return NPERR_NO_ERROR;
2036 case NPNVPluginElementNPObject: {
2037 *(NPObject **)result = _getpluginelement(npp);
2039 return NPERR_NO_ERROR;
2042 case NPNVSupportsWindowless: {
2043 #if defined(XP_WIN) || defined(XP_MACOSX) || (defined(MOZ_X11) && defined(MOZ_WIDGET_GTK2))
2044 *(NPBool*)result = PR_TRUE;
2045 #else
2046 *(NPBool*)result = PR_FALSE;
2047 #endif
2048 return NPERR_NO_ERROR;
2051 #ifdef XP_MACOSX
2052 case NPNVpluginDrawingModel: {
2053 if (npp) {
2054 nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance*)npp->ndata;
2055 if (inst) {
2056 *(NPDrawingModel*)result = inst->GetDrawingModel();
2057 return NPERR_NO_ERROR;
2060 else {
2061 return NPERR_GENERIC_ERROR;
2065 #ifndef NP_NO_QUICKDRAW
2066 case NPNVsupportsQuickDrawBool: {
2067 *(NPBool*)result = PR_TRUE;
2069 return NPERR_NO_ERROR;
2071 #endif
2073 case NPNVsupportsCoreGraphicsBool: {
2074 *(NPBool*)result = PR_TRUE;
2076 return NPERR_NO_ERROR;
2078 #endif
2080 default:
2081 return NPERR_GENERIC_ERROR;
2085 NPError NP_CALLBACK
2086 _setvalue(NPP npp, NPPVariable variable, void *result)
2088 if (!NS_IsMainThread()) {
2089 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_setvalue called from the wrong thread\n"));
2090 return NPERR_INVALID_PARAM;
2092 NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_SetValue: npp=%p, var=%d\n",
2093 (void*)npp, (int)variable));
2095 if (!npp)
2096 return NPERR_INVALID_INSTANCE_ERROR;
2098 nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) npp->ndata;
2100 NS_ASSERTION(inst, "null instance");
2102 if (!inst)
2103 return NPERR_INVALID_INSTANCE_ERROR;
2105 PluginDestructionGuard guard(inst);
2107 switch (variable) {
2109 // we should keep backward compatibility with NPAPI where the
2110 // actual pointer value is checked rather than its content
2111 // when passing booleans
2112 case NPPVpluginWindowBool: {
2113 #ifdef XP_MACOSX
2114 // This setting doesn't apply to OS X (only to Windows and Unix/Linux).
2115 // See https://developer.mozilla.org/En/NPN_SetValue#section_5. Return
2116 // NPERR_NO_ERROR here to conform to other browsers' behavior on OS X
2117 // (e.g. Safari and Opera).
2118 return NPERR_NO_ERROR;
2119 #else
2120 NPBool bWindowless = (result == nsnull);
2121 return inst->SetWindowless(bWindowless);
2122 #endif
2125 case NPPVpluginTransparentBool: {
2126 NPBool bTransparent = (result != nsnull);
2127 return inst->SetTransparent(bTransparent);
2130 case NPPVjavascriptPushCallerBool:
2132 nsresult rv;
2133 nsCOMPtr<nsIJSContextStack> contextStack =
2134 do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
2135 if (NS_SUCCEEDED(rv)) {
2136 NPBool bPushCaller = (result != nsnull);
2138 if (bPushCaller) {
2139 rv = NS_ERROR_FAILURE;
2141 nsCOMPtr<nsIPluginInstancePeer> peer;
2142 if (NS_SUCCEEDED(inst->GetPeer(getter_AddRefs(peer))) && peer) {
2143 nsCOMPtr<nsIPluginInstancePeer2> peer2 =
2144 do_QueryInterface(peer);
2146 if (peer2) {
2147 JSContext *cx;
2148 rv = peer2->GetJSContext(&cx);
2150 if (NS_SUCCEEDED(rv))
2151 rv = contextStack->Push(cx);
2154 } else {
2155 rv = contextStack->Pop(nsnull);
2158 return NS_SUCCEEDED(rv) ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR;
2161 case NPPVpluginKeepLibraryInMemory: {
2162 NPBool bCached = (result != nsnull);
2163 return inst->SetCached(bCached);
2166 case NPPVpluginWantsAllNetworkStreams: {
2167 PRBool bWantsAllNetworkStreams = (result != nsnull);
2168 return inst->SetWantsAllNetworkStreams(bWantsAllNetworkStreams);
2171 #ifdef XP_MACOSX
2172 case NPPVpluginDrawingModel: {
2173 if (inst) {
2174 int dModelValue = (int)result;
2175 inst->SetDrawingModel((NPDrawingModel)dModelValue);
2176 return NPERR_NO_ERROR;
2178 else {
2179 return NPERR_GENERIC_ERROR;
2182 #endif
2184 default:
2185 return NPERR_NO_ERROR;
2189 NPError NP_CALLBACK
2190 _requestread(NPStream *pstream, NPByteRange *rangeList)
2192 if (!NS_IsMainThread()) {
2193 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_requestread called from the wrong thread\n"));
2194 return NPERR_INVALID_PARAM;
2196 NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_RequestRead: stream=%p\n",
2197 (void*)pstream));
2199 #ifdef PLUGIN_LOGGING
2200 for(NPByteRange * range = rangeList; range != nsnull; range = range->next)
2201 PR_LOG(nsPluginLogging::gNPNLog,PLUGIN_LOG_NOISY,
2202 ("%i-%i", range->offset, range->offset + range->length - 1));
2204 PR_LOG(nsPluginLogging::gNPNLog,PLUGIN_LOG_NOISY, ("\n\n"));
2205 PR_LogFlush();
2206 #endif
2208 if (!pstream || !rangeList || !pstream->ndata)
2209 return NPERR_INVALID_PARAM;
2211 nsNPAPIPluginStreamListener* streamlistener = (nsNPAPIPluginStreamListener*)pstream->ndata;
2213 nsPluginStreamType streamtype = nsPluginStreamType_Normal;
2215 streamlistener->GetStreamType(&streamtype);
2217 if (streamtype != nsPluginStreamType_Seek)
2218 return NPERR_STREAM_NOT_SEEKABLE;
2220 if (streamlistener->mStreamInfo)
2221 streamlistener->mStreamInfo->RequestRead((nsByteRange *)rangeList);
2223 return NS_OK;
2226 // Deprecated, only stubbed out
2227 void* NP_CALLBACK /* OJI type: JRIEnv* */
2228 _getJavaEnv(void)
2230 NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetJavaEnv\n"));
2231 return NULL;
2234 const char * NP_CALLBACK
2235 _useragent(NPP npp)
2237 if (!NS_IsMainThread()) {
2238 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_useragent called from the wrong thread\n"));
2239 return nsnull;
2241 NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_UserAgent: npp=%p\n", (void*)npp));
2243 nsCOMPtr<nsIPluginManager> pm(do_GetService(kPluginManagerCID));
2244 if (!pm)
2245 return nsnull;
2247 const char *retstr;
2248 nsresult rv = pm->UserAgent(&retstr);
2249 if (NS_FAILED(rv))
2250 return nsnull;
2252 return retstr;
2255 void * NP_CALLBACK
2256 _memalloc (uint32_t size)
2258 if (!NS_IsMainThread()) {
2259 NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,("NPN_memalloc called from the wrong thread\n"));
2261 NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_MemAlloc: size=%d\n", size));
2262 return nsMemory::Alloc(size);
2265 // Deprecated, only stubbed out
2266 void* NP_CALLBACK /* OJI type: jref */
2267 _getJavaPeer(NPP npp)
2269 NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetJavaPeer: npp=%p\n", (void*)npp));
2270 return NULL;
2273 void NP_CALLBACK
2274 _pushpopupsenabledstate(NPP npp, NPBool enabled)
2276 if (!NS_IsMainThread()) {
2277 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_pushpopupsenabledstate called from the wrong thread\n"));
2278 return;
2280 nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)npp->ndata;
2281 if (!inst)
2282 return;
2284 inst->PushPopupsEnabledState(enabled);
2287 void NP_CALLBACK
2288 _poppopupsenabledstate(NPP npp)
2290 if (!NS_IsMainThread()) {
2291 NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_poppopupsenabledstate called from the wrong thread\n"));
2292 return;
2294 nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)npp->ndata;
2295 if (!inst)
2296 return;
2298 inst->PopPopupsEnabledState();
2301 class nsPluginThreadRunnable : public nsRunnable,
2302 public PRCList
2304 public:
2305 nsPluginThreadRunnable(NPP instance, PluginThreadCallback func,
2306 void *userData);
2307 virtual ~nsPluginThreadRunnable();
2309 NS_IMETHOD Run();
2311 PRBool IsForInstance(NPP instance)
2313 return (mInstance == instance);
2316 void Invalidate()
2318 mFunc = nsnull;
2321 PRBool IsValid()
2323 return (mFunc != nsnull);
2326 private:
2327 NPP mInstance;
2328 PluginThreadCallback mFunc;
2329 void *mUserData;
2332 nsPluginThreadRunnable::nsPluginThreadRunnable(NPP instance,
2333 PluginThreadCallback func,
2334 void *userData)
2335 : mInstance(instance), mFunc(func), mUserData(userData)
2337 if (!sPluginThreadAsyncCallLock) {
2338 // Failed to create lock, not much we can do here then...
2339 mFunc = nsnull;
2341 return;
2344 PR_INIT_CLIST(this);
2347 nsAutoLock lock(sPluginThreadAsyncCallLock);
2349 nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
2350 if (!inst || !inst->IsStarted()) {
2351 // The plugin was stopped, ignore this async call.
2352 mFunc = nsnull;
2354 return;
2357 PR_APPEND_LINK(this, &sPendingAsyncCalls);
2361 nsPluginThreadRunnable::~nsPluginThreadRunnable()
2363 if (!sPluginThreadAsyncCallLock) {
2364 return;
2368 nsAutoLock lock(sPluginThreadAsyncCallLock);
2370 PR_REMOVE_LINK(this);
2374 NS_IMETHODIMP
2375 nsPluginThreadRunnable::Run()
2377 if (mFunc) {
2378 PluginDestructionGuard guard(mInstance);
2380 NS_TRY_SAFE_CALL_VOID(mFunc(mUserData), nsnull, nsnull);
2383 return NS_OK;
2386 void NP_CALLBACK
2387 _pluginthreadasynccall(NPP instance, PluginThreadCallback func, void *userData)
2389 if (NS_IsMainThread()) {
2390 NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,("NPN_pluginthreadasynccall called from the main thread\n"));
2391 } else {
2392 NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,("NPN_pluginthreadasynccall called from a non main thread\n"));
2394 nsRefPtr<nsPluginThreadRunnable> evt =
2395 new nsPluginThreadRunnable(instance, func, userData);
2397 if (evt && evt->IsValid()) {
2398 NS_DispatchToMainThread(evt);
2402 void
2403 OnPluginDestroy(NPP instance)
2405 if (!sPluginThreadAsyncCallLock) {
2406 return;
2410 nsAutoLock lock(sPluginThreadAsyncCallLock);
2412 if (PR_CLIST_IS_EMPTY(&sPendingAsyncCalls)) {
2413 return;
2416 nsPluginThreadRunnable *r =
2417 (nsPluginThreadRunnable *)PR_LIST_HEAD(&sPendingAsyncCalls);
2419 do {
2420 if (r->IsForInstance(instance)) {
2421 r->Invalidate();
2424 r = (nsPluginThreadRunnable *)PR_NEXT_LINK(r);
2425 } while (r != &sPendingAsyncCalls);
2429 void
2430 OnShutdown()
2432 NS_ASSERTION(PR_CLIST_IS_EMPTY(&sPendingAsyncCalls),
2433 "Pending async plugin call list not cleaned up!");
2435 if (sPluginThreadAsyncCallLock) {
2436 nsAutoLock::DestroyLock(sPluginThreadAsyncCallLock);
2438 sPluginThreadAsyncCallLock = nsnull;
2442 void
2443 EnterAsyncPluginThreadCallLock()
2445 if (sPluginThreadAsyncCallLock) {
2446 PR_Lock(sPluginThreadAsyncCallLock);
2450 void
2451 ExitAsyncPluginThreadCallLock()
2453 if (sPluginThreadAsyncCallLock) {
2454 PR_Unlock(sPluginThreadAsyncCallLock);
2458 NPP NPPStack::sCurrentNPP = nsnull;