michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "base/basictypes.h" michael@0: michael@0: /* This must occur *after* layers/PLayerTransaction.h to avoid typedefs conflicts. */ michael@0: #include "mozilla/ArrayUtils.h" michael@0: michael@0: #include "pratom.h" michael@0: #include "prmem.h" michael@0: #include "prenv.h" michael@0: #include "prclist.h" michael@0: michael@0: #include "jsfriendapi.h" michael@0: michael@0: #include "nsPluginHost.h" michael@0: #include "nsNPAPIPlugin.h" michael@0: #include "nsNPAPIPluginInstance.h" michael@0: #include "nsNPAPIPluginStreamListener.h" michael@0: #include "nsPluginStreamListenerPeer.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "nsPluginInstanceOwner.h" michael@0: michael@0: #include "nsPluginsDir.h" michael@0: #include "nsPluginLogging.h" michael@0: michael@0: #include "nsIDOMElement.h" michael@0: #include "nsPIDOMWindow.h" michael@0: #include "nsGlobalWindow.h" michael@0: #include "nsIDocument.h" michael@0: #include "nsIContent.h" michael@0: #include "nsIScriptGlobalObject.h" michael@0: #include "nsIScriptContext.h" michael@0: #include "nsIUnicodeNormalizer.h" michael@0: #include "nsDOMJSUtils.h" michael@0: #include "nsIPrincipal.h" michael@0: #include "nsWildCard.h" michael@0: #include "nsContentUtils.h" michael@0: #include "nsCxPusher.h" michael@0: michael@0: #include "nsIXPConnect.h" michael@0: michael@0: #include "nsIObserverService.h" michael@0: #include michael@0: michael@0: #ifdef MOZ_WIDGET_COCOA michael@0: #include michael@0: #include michael@0: #include michael@0: #include "nsCocoaFeatures.h" michael@0: #endif michael@0: michael@0: // needed for nppdf plugin michael@0: #if (MOZ_WIDGET_GTK) michael@0: #include michael@0: #include michael@0: #if (MOZ_WIDGET_GTK == 2) michael@0: #include "gtk2xtbin.h" michael@0: #endif michael@0: #endif michael@0: michael@0: #include "nsJSUtils.h" michael@0: #include "nsJSNPRuntime.h" michael@0: #include "nsIHttpAuthManager.h" michael@0: #include "nsICookieService.h" michael@0: #include "nsILoadContext.h" michael@0: #include "nsIDocShell.h" michael@0: michael@0: #include "nsNetUtil.h" michael@0: michael@0: #include "mozilla/Mutex.h" michael@0: #include "mozilla/PluginLibrary.h" michael@0: using mozilla::PluginLibrary; michael@0: michael@0: #include "mozilla/PluginPRLibrary.h" michael@0: using mozilla::PluginPRLibrary; michael@0: michael@0: #include "mozilla/plugins/PluginModuleParent.h" michael@0: using mozilla::plugins::PluginModuleParent; michael@0: michael@0: #ifdef MOZ_X11 michael@0: #include "mozilla/X11Util.h" michael@0: #endif michael@0: michael@0: #ifdef XP_WIN michael@0: #include michael@0: #include "mozilla/WindowsVersion.h" michael@0: #ifdef ACCESSIBILITY michael@0: #include "mozilla/a11y/Compatibility.h" michael@0: #endif michael@0: #endif michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: #include michael@0: #include "android_npapi.h" michael@0: #include "ANPBase.h" michael@0: #include "AndroidBridge.h" michael@0: #undef LOG michael@0: #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args) michael@0: #endif michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::plugins::parent; michael@0: michael@0: // We should make this const... michael@0: static NPNetscapeFuncs sBrowserFuncs = { michael@0: sizeof(sBrowserFuncs), michael@0: (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR, michael@0: _geturl, michael@0: _posturl, michael@0: _requestread, michael@0: _newstream, michael@0: _write, michael@0: _destroystream, michael@0: _status, michael@0: _useragent, michael@0: _memalloc, michael@0: _memfree, michael@0: _memflush, michael@0: _reloadplugins, michael@0: _getJavaEnv, michael@0: _getJavaPeer, michael@0: _geturlnotify, michael@0: _posturlnotify, michael@0: _getvalue, michael@0: _setvalue, michael@0: _invalidaterect, michael@0: _invalidateregion, michael@0: _forceredraw, michael@0: _getstringidentifier, michael@0: _getstringidentifiers, michael@0: _getintidentifier, michael@0: _identifierisstring, michael@0: _utf8fromidentifier, michael@0: _intfromidentifier, michael@0: _createobject, michael@0: _retainobject, michael@0: _releaseobject, michael@0: _invoke, michael@0: _invokeDefault, michael@0: _evaluate, michael@0: _getproperty, michael@0: _setproperty, michael@0: _removeproperty, michael@0: _hasproperty, michael@0: _hasmethod, michael@0: _releasevariantvalue, michael@0: _setexception, michael@0: _pushpopupsenabledstate, michael@0: _poppopupsenabledstate, michael@0: _enumerate, michael@0: _pluginthreadasynccall, michael@0: _construct, michael@0: _getvalueforurl, michael@0: _setvalueforurl, michael@0: _getauthenticationinfo, michael@0: _scheduletimer, michael@0: _unscheduletimer, michael@0: _popupcontextmenu, michael@0: _convertpoint, michael@0: nullptr, // handleevent, unimplemented michael@0: nullptr, // unfocusinstance, unimplemented michael@0: _urlredirectresponse, michael@0: _initasyncsurface, michael@0: _finalizeasyncsurface, michael@0: _setcurrentasyncsurface michael@0: }; michael@0: michael@0: static Mutex *sPluginThreadAsyncCallLock = nullptr; michael@0: static PRCList sPendingAsyncCalls = PR_INIT_STATIC_CLIST(&sPendingAsyncCalls); michael@0: michael@0: // POST/GET stream type michael@0: enum eNPPStreamTypeInternal { michael@0: eNPPStreamTypeInternal_Get, michael@0: eNPPStreamTypeInternal_Post michael@0: }; michael@0: michael@0: PRIntervalTime NS_NotifyBeginPluginCall(NSPluginCallReentry aReentryState) michael@0: { michael@0: nsNPAPIPluginInstance::BeginPluginCall(aReentryState); michael@0: return PR_IntervalNow(); michael@0: } michael@0: michael@0: // This function sends a notification using the observer service to any object michael@0: // registered to listen to the "experimental-notify-plugin-call" subject. michael@0: // Each "experimental-notify-plugin-call" notification carries with it the run michael@0: // time value in milliseconds that the call took to execute. michael@0: void NS_NotifyPluginCall(PRIntervalTime startTime, NSPluginCallReentry aReentryState) michael@0: { michael@0: nsNPAPIPluginInstance::EndPluginCall(aReentryState); michael@0: michael@0: PRIntervalTime endTime = PR_IntervalNow() - startTime; michael@0: nsCOMPtr notifyUIService = michael@0: mozilla::services::GetObserverService(); michael@0: if (!notifyUIService) michael@0: return; michael@0: michael@0: float runTimeInSeconds = float(endTime) / PR_TicksPerSecond(); michael@0: nsAutoString runTimeString; michael@0: runTimeString.AppendFloat(runTimeInSeconds); michael@0: const char16_t* runTime = runTimeString.get(); michael@0: notifyUIService->NotifyObservers(nullptr, "experimental-notify-plugin-call", michael@0: runTime); michael@0: } michael@0: michael@0: static void CheckClassInitialized() michael@0: { michael@0: static bool initialized = false; michael@0: michael@0: if (initialized) michael@0: return; michael@0: michael@0: if (!sPluginThreadAsyncCallLock) michael@0: sPluginThreadAsyncCallLock = new Mutex("nsNPAPIPlugin.sPluginThreadAsyncCallLock"); michael@0: michael@0: initialized = true; michael@0: michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,("NPN callbacks initialized\n")); michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS0(nsNPAPIPlugin) michael@0: michael@0: nsNPAPIPlugin::nsNPAPIPlugin() michael@0: { michael@0: memset((void*)&mPluginFuncs, 0, sizeof(mPluginFuncs)); michael@0: mPluginFuncs.size = sizeof(mPluginFuncs); michael@0: mPluginFuncs.version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR; michael@0: michael@0: mLibrary = nullptr; michael@0: } michael@0: michael@0: nsNPAPIPlugin::~nsNPAPIPlugin() michael@0: { michael@0: delete mLibrary; michael@0: mLibrary = nullptr; michael@0: } michael@0: michael@0: void michael@0: nsNPAPIPlugin::PluginCrashed(const nsAString& pluginDumpID, michael@0: const nsAString& browserDumpID) michael@0: { michael@0: nsRefPtr host = nsPluginHost::GetInst(); michael@0: host->PluginCrashed(this, pluginDumpID, browserDumpID); michael@0: } michael@0: michael@0: bool michael@0: nsNPAPIPlugin::RunPluginOOP(const nsPluginTag *aPluginTag) michael@0: { michael@0: if (PR_GetEnv("MOZ_DISABLE_OOP_PLUGINS")) { michael@0: return false; michael@0: } michael@0: michael@0: if (!aPluginTag) { michael@0: return false; michael@0: } michael@0: michael@0: #ifdef ACCESSIBILITY michael@0: // Certain assistive technologies don't want oop Flash, thus we have a special michael@0: // pref for them to disable oop Flash (refer to bug 785047 for details). michael@0: bool useA11yPref = false; michael@0: #ifdef XP_WIN michael@0: useA11yPref = a11y::Compatibility::IsJAWS(); michael@0: #endif michael@0: #endif michael@0: michael@0: #ifdef XP_WIN michael@0: // On Windows Vista+, we force Flash to run in OOPP mode because Adobe michael@0: // doesn't test Flash in-process and there are known stability bugs. michael@0: if (aPluginTag->mIsFlashPlugin && IsVistaOrLater()) { michael@0: #ifdef ACCESSIBILITY michael@0: if (!useA11yPref) michael@0: return true; michael@0: #else michael@0: return true; michael@0: #endif michael@0: } michael@0: #endif michael@0: michael@0: nsIPrefBranch* prefs = Preferences::GetRootBranch(); michael@0: if (!prefs) { michael@0: return false; michael@0: } michael@0: michael@0: // Get per-library whitelist/blacklist pref string michael@0: // "dom.ipc.plugins.enabled.filename.dll" and fall back to the default value michael@0: // of "dom.ipc.plugins.enabled" michael@0: // The "filename.dll" part can contain shell wildcard pattern michael@0: michael@0: nsAutoCString prefFile(aPluginTag->mFullPath.get()); michael@0: int32_t slashPos = prefFile.RFindCharInSet("/\\"); michael@0: if (kNotFound == slashPos) michael@0: return false; michael@0: prefFile.Cut(0, slashPos + 1); michael@0: ToLowerCase(prefFile); michael@0: michael@0: #ifdef XP_MACOSX michael@0: #if defined(__i386__) michael@0: nsAutoCString prefGroupKey("dom.ipc.plugins.enabled.i386."); michael@0: #elif defined(__x86_64__) michael@0: nsAutoCString prefGroupKey("dom.ipc.plugins.enabled.x86_64."); michael@0: #elif defined(__ppc__) michael@0: nsAutoCString prefGroupKey("dom.ipc.plugins.enabled.ppc."); michael@0: #endif michael@0: #else michael@0: nsAutoCString prefGroupKey("dom.ipc.plugins.enabled."); michael@0: #endif michael@0: michael@0: #ifdef ACCESSIBILITY michael@0: if (useA11yPref) michael@0: prefGroupKey.AssignLiteral("dom.ipc.plugins.enabled.a11y."); michael@0: #endif michael@0: michael@0: // Java plugins include a number of different file names, michael@0: // so use the mime type (mIsJavaPlugin) and a special pref. michael@0: if (aPluginTag->mIsJavaPlugin && michael@0: !Preferences::GetBool("dom.ipc.plugins.java.enabled", true)) { michael@0: return false; michael@0: } michael@0: michael@0: uint32_t prefCount; michael@0: char** prefNames; michael@0: nsresult rv = prefs->GetChildList(prefGroupKey.get(), michael@0: &prefCount, &prefNames); michael@0: michael@0: bool oopPluginsEnabled = false; michael@0: bool prefSet = false; michael@0: michael@0: if (NS_SUCCEEDED(rv) && prefCount > 0) { michael@0: uint32_t prefixLength = prefGroupKey.Length(); michael@0: for (uint32_t currentPref = 0; currentPref < prefCount; currentPref++) { michael@0: // Get the mask michael@0: const char* maskStart = prefNames[currentPref] + prefixLength; michael@0: bool match = false; michael@0: michael@0: int valid = NS_WildCardValid(maskStart); michael@0: if (valid == INVALID_SXP) { michael@0: continue; michael@0: } michael@0: else if(valid == NON_SXP) { michael@0: // mask is not a shell pattern, compare it as normal string michael@0: match = (strcmp(prefFile.get(), maskStart) == 0); michael@0: } michael@0: else { michael@0: match = (NS_WildCardMatch(prefFile.get(), maskStart, 0) == MATCH); michael@0: } michael@0: michael@0: if (match && NS_SUCCEEDED(Preferences::GetBool(prefNames[currentPref], michael@0: &oopPluginsEnabled))) { michael@0: prefSet = true; michael@0: break; michael@0: } michael@0: } michael@0: NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, prefNames); michael@0: } michael@0: michael@0: if (!prefSet) { michael@0: oopPluginsEnabled = michael@0: #ifdef XP_MACOSX michael@0: #if defined(__i386__) michael@0: Preferences::GetBool("dom.ipc.plugins.enabled.i386", false); michael@0: #elif defined(__x86_64__) michael@0: Preferences::GetBool("dom.ipc.plugins.enabled.x86_64", false); michael@0: #elif defined(__ppc__) michael@0: Preferences::GetBool("dom.ipc.plugins.enabled.ppc", false); michael@0: #endif michael@0: #else michael@0: #ifdef ACCESSIBILITY michael@0: useA11yPref ? Preferences::GetBool("dom.ipc.plugins.enabled.a11y", false) : michael@0: #endif michael@0: Preferences::GetBool("dom.ipc.plugins.enabled", false); michael@0: #endif michael@0: } michael@0: michael@0: return oopPluginsEnabled; michael@0: } michael@0: michael@0: inline PluginLibrary* michael@0: GetNewPluginLibrary(nsPluginTag *aPluginTag) michael@0: { michael@0: if (!aPluginTag) { michael@0: return nullptr; michael@0: } michael@0: michael@0: if (nsNPAPIPlugin::RunPluginOOP(aPluginTag)) { michael@0: return PluginModuleParent::LoadModule(aPluginTag->mFullPath.get()); michael@0: } michael@0: return new PluginPRLibrary(aPluginTag->mFullPath.get(), aPluginTag->mLibrary); michael@0: } michael@0: michael@0: // Creates an nsNPAPIPlugin object. One nsNPAPIPlugin object exists per plugin (not instance). michael@0: nsresult michael@0: nsNPAPIPlugin::CreatePlugin(nsPluginTag *aPluginTag, nsNPAPIPlugin** aResult) michael@0: { michael@0: *aResult = nullptr; michael@0: michael@0: if (!aPluginTag) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: CheckClassInitialized(); michael@0: michael@0: nsRefPtr plugin = new nsNPAPIPlugin(); michael@0: if (!plugin) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: PluginLibrary* pluginLib = GetNewPluginLibrary(aPluginTag); michael@0: if (!pluginLib) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: #if defined(XP_MACOSX) || defined(MOZ_WIDGET_ANDROID) michael@0: if (!pluginLib->HasRequiredFunctions()) { michael@0: NS_WARNING("Not all necessary functions exposed by plugin, it will not load."); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: #endif michael@0: michael@0: plugin->mLibrary = pluginLib; michael@0: pluginLib->SetPlugin(plugin); michael@0: michael@0: NPError pluginCallError; michael@0: nsresult rv; michael@0: michael@0: // Exchange NPAPI entry points. michael@0: #if defined(XP_WIN) michael@0: // NP_GetEntryPoints must be called before NP_Initialize on Windows. michael@0: rv = pluginLib->NP_GetEntryPoints(&plugin->mPluginFuncs, &pluginCallError); michael@0: if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // NP_Initialize must be called after NP_GetEntryPoints on Windows. michael@0: rv = pluginLib->NP_Initialize(&sBrowserFuncs, &pluginCallError); michael@0: if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: #elif defined(XP_MACOSX) michael@0: // NP_Initialize must be called before NP_GetEntryPoints on Mac OS X. michael@0: // We need to match WebKit's behavior. michael@0: rv = pluginLib->NP_Initialize(&sBrowserFuncs, &pluginCallError); michael@0: if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: rv = pluginLib->NP_GetEntryPoints(&plugin->mPluginFuncs, &pluginCallError); michael@0: if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: #elif defined(MOZ_WIDGET_GONK) michael@0: #else michael@0: rv = pluginLib->NP_Initialize(&sBrowserFuncs, &plugin->mPluginFuncs, &pluginCallError); michael@0: if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: #endif michael@0: michael@0: plugin.forget(aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: PluginLibrary* michael@0: nsNPAPIPlugin::GetLibrary() michael@0: { michael@0: return mLibrary; michael@0: } michael@0: michael@0: NPPluginFuncs* michael@0: nsNPAPIPlugin::PluginFuncs() michael@0: { michael@0: return &mPluginFuncs; michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPlugin::Shutdown() michael@0: { michael@0: NPP_PLUGIN_LOG(PLUGIN_LOG_BASIC, michael@0: ("NPP Shutdown to be called: this=%p\n", this)); michael@0: michael@0: NPError shutdownError; michael@0: mLibrary->NP_Shutdown(&shutdownError); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPlugin::RetainStream(NPStream *pstream, nsISupports **aRetainedPeer) michael@0: { michael@0: if (!aRetainedPeer) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: *aRetainedPeer = nullptr; michael@0: michael@0: if (!pstream || !pstream->ndata) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: nsNPAPIStreamWrapper* streamWrapper = static_cast(pstream->ndata); michael@0: nsNPAPIPluginStreamListener* listener = streamWrapper->GetStreamListener(); michael@0: if (!listener) { michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: nsIStreamListener* streamListener = listener->GetStreamListenerPeer(); michael@0: if (!streamListener) { michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: *aRetainedPeer = streamListener; michael@0: NS_ADDREF(*aRetainedPeer); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Create a new NPP GET or POST (given in the type argument) url michael@0: // stream that may have a notify callback michael@0: NPError michael@0: MakeNewNPAPIStreamInternal(NPP npp, const char *relativeURL, const char *target, michael@0: eNPPStreamTypeInternal type, michael@0: bool bDoNotify = false, michael@0: void *notifyData = nullptr, uint32_t len = 0, michael@0: const char *buf = nullptr, NPBool file = false) michael@0: { michael@0: if (!npp) michael@0: return NPERR_INVALID_INSTANCE_ERROR; michael@0: michael@0: PluginDestructionGuard guard(npp); michael@0: michael@0: nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) npp->ndata; michael@0: if (!inst || !inst->IsRunning()) michael@0: return NPERR_INVALID_INSTANCE_ERROR; michael@0: michael@0: nsCOMPtr pluginHostCOM = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID); michael@0: nsPluginHost *pluginHost = static_cast(pluginHostCOM.get()); michael@0: if (!pluginHost) { michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: nsRefPtr listener; michael@0: // Set aCallNotify here to false. If pluginHost->GetURL or PostURL fail, michael@0: // the listener's destructor will do the notification while we are about to michael@0: // return a failure code. michael@0: // Call SetCallNotify(true) below after we are sure we cannot return a failure michael@0: // code. michael@0: if (!target) { michael@0: inst->NewStreamListener(relativeURL, notifyData, michael@0: getter_AddRefs(listener)); michael@0: if (listener) { michael@0: listener->SetCallNotify(false); michael@0: } michael@0: } michael@0: michael@0: switch (type) { michael@0: case eNPPStreamTypeInternal_Get: michael@0: { michael@0: if (NS_FAILED(pluginHost->GetURL(inst, relativeURL, target, listener, michael@0: nullptr, nullptr, false))) michael@0: return NPERR_GENERIC_ERROR; michael@0: break; michael@0: } michael@0: case eNPPStreamTypeInternal_Post: michael@0: { michael@0: if (NS_FAILED(pluginHost->PostURL(inst, relativeURL, len, buf, file, michael@0: target, listener, nullptr, nullptr, michael@0: false, 0, nullptr))) michael@0: return NPERR_GENERIC_ERROR; michael@0: break; michael@0: } michael@0: default: michael@0: NS_ERROR("how'd I get here"); michael@0: } michael@0: michael@0: if (listener) { michael@0: // SetCallNotify(bDoNotify) here, see comment above. michael@0: listener->SetCallNotify(bDoNotify); michael@0: } michael@0: michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: #if defined(MOZ_MEMORY_WINDOWS) michael@0: extern "C" size_t malloc_usable_size(const void *ptr); michael@0: #endif michael@0: michael@0: namespace { michael@0: michael@0: static char *gNPPException; michael@0: michael@0: class nsPluginThreadRunnable : public nsRunnable, michael@0: public PRCList michael@0: { michael@0: public: michael@0: nsPluginThreadRunnable(NPP instance, PluginThreadCallback func, michael@0: void *userData); michael@0: virtual ~nsPluginThreadRunnable(); michael@0: michael@0: NS_IMETHOD Run(); michael@0: michael@0: bool IsForInstance(NPP instance) michael@0: { michael@0: return (mInstance == instance); michael@0: } michael@0: michael@0: void Invalidate() michael@0: { michael@0: mFunc = nullptr; michael@0: } michael@0: michael@0: bool IsValid() michael@0: { michael@0: return (mFunc != nullptr); michael@0: } michael@0: michael@0: private: michael@0: NPP mInstance; michael@0: PluginThreadCallback mFunc; michael@0: void *mUserData; michael@0: }; michael@0: michael@0: static nsIDocument * michael@0: GetDocumentFromNPP(NPP npp) michael@0: { michael@0: NS_ENSURE_TRUE(npp, nullptr); michael@0: michael@0: nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)npp->ndata; michael@0: NS_ENSURE_TRUE(inst, nullptr); michael@0: michael@0: PluginDestructionGuard guard(inst); michael@0: michael@0: nsRefPtr owner = inst->GetOwner(); michael@0: NS_ENSURE_TRUE(owner, nullptr); michael@0: michael@0: nsCOMPtr doc; michael@0: owner->GetDocument(getter_AddRefs(doc)); michael@0: michael@0: return doc; michael@0: } michael@0: michael@0: static JSContext * michael@0: GetJSContextFromDoc(nsIDocument *doc) michael@0: { michael@0: nsCOMPtr sgo = do_QueryInterface(doc->GetWindow()); michael@0: NS_ENSURE_TRUE(sgo, nullptr); michael@0: michael@0: nsIScriptContext *scx = sgo->GetContext(); michael@0: NS_ENSURE_TRUE(scx, nullptr); michael@0: michael@0: return scx->GetNativeContext(); michael@0: } michael@0: michael@0: static JSContext * michael@0: GetJSContextFromNPP(NPP npp) michael@0: { michael@0: nsIDocument *doc = GetDocumentFromNPP(npp); michael@0: NS_ENSURE_TRUE(doc, nullptr); michael@0: michael@0: return GetJSContextFromDoc(doc); michael@0: } michael@0: michael@0: static already_AddRefed michael@0: GetChannelFromNPP(NPP npp) michael@0: { michael@0: nsCOMPtr doc = GetDocumentFromNPP(npp); michael@0: if (!doc) michael@0: return nullptr; michael@0: nsCOMPtr domwindow = doc->GetWindow(); michael@0: nsCOMPtr channel; michael@0: if (domwindow) { michael@0: nsCOMPtr docShell = domwindow->GetDocShell(); michael@0: if (docShell) { michael@0: docShell->GetCurrentDocumentChannel(getter_AddRefs(channel)); michael@0: } michael@0: } michael@0: return channel.forget(); michael@0: } michael@0: michael@0: static NPIdentifier michael@0: doGetIdentifier(JSContext *cx, const NPUTF8* name) michael@0: { michael@0: NS_ConvertUTF8toUTF16 utf16name(name); michael@0: michael@0: JSString *str = ::JS_InternUCStringN(cx, utf16name.get(), utf16name.Length()); michael@0: michael@0: if (!str) michael@0: return nullptr; michael@0: michael@0: return StringToNPIdentifier(cx, str); michael@0: } michael@0: michael@0: #if defined(MOZ_MEMORY_WINDOWS) michael@0: BOOL michael@0: InHeap(HANDLE hHeap, LPVOID lpMem) michael@0: { michael@0: BOOL success = FALSE; michael@0: PROCESS_HEAP_ENTRY he; michael@0: he.lpData = nullptr; michael@0: while (HeapWalk(hHeap, &he) != 0) { michael@0: if (he.lpData == lpMem) { michael@0: success = TRUE; michael@0: break; michael@0: } michael@0: } michael@0: HeapUnlock(hHeap); michael@0: return success; michael@0: } michael@0: #endif michael@0: michael@0: } /* anonymous namespace */ michael@0: michael@0: NPPExceptionAutoHolder::NPPExceptionAutoHolder() michael@0: : mOldException(gNPPException) michael@0: { michael@0: gNPPException = nullptr; michael@0: } michael@0: michael@0: NPPExceptionAutoHolder::~NPPExceptionAutoHolder() michael@0: { michael@0: NS_ASSERTION(!gNPPException, "NPP exception not properly cleared!"); michael@0: michael@0: gNPPException = mOldException; michael@0: } michael@0: michael@0: nsPluginThreadRunnable::nsPluginThreadRunnable(NPP instance, michael@0: PluginThreadCallback func, michael@0: void *userData) michael@0: : mInstance(instance), mFunc(func), mUserData(userData) michael@0: { michael@0: if (!sPluginThreadAsyncCallLock) { michael@0: // Failed to create lock, not much we can do here then... michael@0: mFunc = nullptr; michael@0: michael@0: return; michael@0: } michael@0: michael@0: PR_INIT_CLIST(this); michael@0: michael@0: { michael@0: MutexAutoLock lock(*sPluginThreadAsyncCallLock); michael@0: michael@0: nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata; michael@0: if (!inst || !inst->IsRunning()) { michael@0: // The plugin was stopped, ignore this async call. michael@0: mFunc = nullptr; michael@0: michael@0: return; michael@0: } michael@0: michael@0: PR_APPEND_LINK(this, &sPendingAsyncCalls); michael@0: } michael@0: } michael@0: michael@0: nsPluginThreadRunnable::~nsPluginThreadRunnable() michael@0: { michael@0: if (!sPluginThreadAsyncCallLock) { michael@0: return; michael@0: } michael@0: michael@0: { michael@0: MutexAutoLock lock(*sPluginThreadAsyncCallLock); michael@0: michael@0: PR_REMOVE_LINK(this); michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPluginThreadRunnable::Run() michael@0: { michael@0: if (mFunc) { michael@0: PluginDestructionGuard guard(mInstance); michael@0: michael@0: NS_TRY_SAFE_CALL_VOID(mFunc(mUserData), nullptr, michael@0: NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: OnPluginDestroy(NPP instance) michael@0: { michael@0: if (!sPluginThreadAsyncCallLock) { michael@0: return; michael@0: } michael@0: michael@0: { michael@0: MutexAutoLock lock(*sPluginThreadAsyncCallLock); michael@0: michael@0: if (PR_CLIST_IS_EMPTY(&sPendingAsyncCalls)) { michael@0: return; michael@0: } michael@0: michael@0: nsPluginThreadRunnable *r = michael@0: (nsPluginThreadRunnable *)PR_LIST_HEAD(&sPendingAsyncCalls); michael@0: michael@0: do { michael@0: if (r->IsForInstance(instance)) { michael@0: r->Invalidate(); michael@0: } michael@0: michael@0: r = (nsPluginThreadRunnable *)PR_NEXT_LINK(r); michael@0: } while (r != &sPendingAsyncCalls); michael@0: } michael@0: } michael@0: michael@0: void michael@0: OnShutdown() michael@0: { michael@0: NS_ASSERTION(PR_CLIST_IS_EMPTY(&sPendingAsyncCalls), michael@0: "Pending async plugin call list not cleaned up!"); michael@0: michael@0: if (sPluginThreadAsyncCallLock) { michael@0: delete sPluginThreadAsyncCallLock; michael@0: michael@0: sPluginThreadAsyncCallLock = nullptr; michael@0: } michael@0: } michael@0: michael@0: AsyncCallbackAutoLock::AsyncCallbackAutoLock() michael@0: { michael@0: if (sPluginThreadAsyncCallLock) { michael@0: sPluginThreadAsyncCallLock->Lock(); michael@0: } michael@0: } michael@0: michael@0: AsyncCallbackAutoLock::~AsyncCallbackAutoLock() michael@0: { michael@0: if (sPluginThreadAsyncCallLock) { michael@0: sPluginThreadAsyncCallLock->Unlock(); michael@0: } michael@0: } michael@0: michael@0: michael@0: NPP NPPStack::sCurrentNPP = nullptr; michael@0: michael@0: const char * michael@0: PeekException() michael@0: { michael@0: return gNPPException; michael@0: } michael@0: michael@0: void michael@0: PopException() michael@0: { michael@0: NS_ASSERTION(gNPPException, "Uh, no NPP exception to pop!"); michael@0: michael@0: if (gNPPException) { michael@0: free(gNPPException); michael@0: michael@0: gNPPException = nullptr; michael@0: } michael@0: } michael@0: michael@0: // michael@0: // Static callbacks that get routed back through the new C++ API michael@0: // michael@0: michael@0: namespace mozilla { michael@0: namespace plugins { michael@0: namespace parent { michael@0: michael@0: NPError michael@0: _geturl(NPP npp, const char* relativeURL, const char* target) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_geturl called from the wrong thread\n")); michael@0: return NPERR_INVALID_PARAM; michael@0: } michael@0: michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, michael@0: ("NPN_GetURL: npp=%p, target=%s, url=%s\n", (void *)npp, target, michael@0: relativeURL)); michael@0: michael@0: PluginDestructionGuard guard(npp); michael@0: michael@0: // Block Adobe Acrobat from loading URLs that are not http:, https:, michael@0: // or ftp: URLs if the given target is null. michael@0: if (!target && relativeURL && michael@0: (strncmp(relativeURL, "http:", 5) != 0) && michael@0: (strncmp(relativeURL, "https:", 6) != 0) && michael@0: (strncmp(relativeURL, "ftp:", 4) != 0)) { michael@0: nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) npp->ndata; michael@0: michael@0: michael@0: const char *name = nullptr; michael@0: nsRefPtr host = nsPluginHost::GetInst(); michael@0: host->GetPluginName(inst, &name); michael@0: michael@0: if (name && strstr(name, "Adobe") && strstr(name, "Acrobat")) { michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: } michael@0: michael@0: return MakeNewNPAPIStreamInternal(npp, relativeURL, target, michael@0: eNPPStreamTypeInternal_Get); michael@0: } michael@0: michael@0: NPError michael@0: _geturlnotify(NPP npp, const char* relativeURL, const char* target, michael@0: void* notifyData) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_geturlnotify called from the wrong thread\n")); michael@0: return NPERR_INVALID_PARAM; michael@0: } michael@0: michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, michael@0: ("NPN_GetURLNotify: npp=%p, target=%s, notify=%p, url=%s\n", (void*)npp, michael@0: target, notifyData, relativeURL)); michael@0: michael@0: PluginDestructionGuard guard(npp); michael@0: michael@0: return MakeNewNPAPIStreamInternal(npp, relativeURL, target, michael@0: eNPPStreamTypeInternal_Get, true, michael@0: notifyData); michael@0: } michael@0: michael@0: NPError michael@0: _posturlnotify(NPP npp, const char *relativeURL, const char *target, michael@0: uint32_t len, const char *buf, NPBool file, void *notifyData) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_posturlnotify called from the wrong thread\n")); michael@0: return NPERR_INVALID_PARAM; michael@0: } michael@0: if (!buf) michael@0: return NPERR_INVALID_PARAM; michael@0: michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, michael@0: ("NPN_PostURLNotify: npp=%p, target=%s, len=%d, file=%d, " michael@0: "notify=%p, url=%s, buf=%s\n", michael@0: (void*)npp, target, len, file, notifyData, relativeURL, michael@0: buf)); michael@0: michael@0: PluginDestructionGuard guard(npp); michael@0: michael@0: return MakeNewNPAPIStreamInternal(npp, relativeURL, target, michael@0: eNPPStreamTypeInternal_Post, true, michael@0: notifyData, len, buf, file); michael@0: } michael@0: michael@0: NPError michael@0: _posturl(NPP npp, const char *relativeURL, const char *target, michael@0: uint32_t len, const char *buf, NPBool file) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_posturl called from the wrong thread\n")); michael@0: return NPERR_INVALID_PARAM; michael@0: } michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, michael@0: ("NPN_PostURL: npp=%p, target=%s, file=%d, len=%d, url=%s, " michael@0: "buf=%s\n", michael@0: (void*)npp, target, file, len, relativeURL, buf)); michael@0: michael@0: PluginDestructionGuard guard(npp); michael@0: michael@0: return MakeNewNPAPIStreamInternal(npp, relativeURL, target, michael@0: eNPPStreamTypeInternal_Post, false, nullptr, michael@0: len, buf, file); michael@0: } michael@0: michael@0: NPError michael@0: _newstream(NPP npp, NPMIMEType type, const char* target, NPStream* *result) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_newstream called from the wrong thread\n")); michael@0: return NPERR_INVALID_PARAM; michael@0: } michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, michael@0: ("NPN_NewStream: npp=%p, type=%s, target=%s\n", (void*)npp, michael@0: (const char *)type, target)); michael@0: michael@0: NPError err = NPERR_INVALID_INSTANCE_ERROR; michael@0: if (npp && npp->ndata) { michael@0: nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance*)npp->ndata; michael@0: michael@0: PluginDestructionGuard guard(inst); michael@0: michael@0: nsCOMPtr stream; michael@0: if (NS_SUCCEEDED(inst->NewStreamFromPlugin((const char*) type, target, michael@0: getter_AddRefs(stream)))) { michael@0: nsNPAPIStreamWrapper* wrapper = new nsNPAPIStreamWrapper(stream, nullptr); michael@0: if (wrapper) { michael@0: (*result) = &wrapper->mNPStream; michael@0: err = NPERR_NO_ERROR; michael@0: } else { michael@0: err = NPERR_OUT_OF_MEMORY_ERROR; michael@0: } michael@0: } else { michael@0: err = NPERR_GENERIC_ERROR; michael@0: } michael@0: } michael@0: return err; michael@0: } michael@0: michael@0: int32_t michael@0: _write(NPP npp, NPStream *pstream, int32_t len, void *buffer) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_write called from the wrong thread\n")); michael@0: return 0; michael@0: } michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, michael@0: ("NPN_Write: npp=%p, url=%s, len=%d, buffer=%s\n", (void*)npp, michael@0: pstream->url, len, (char*)buffer)); michael@0: michael@0: // negative return indicates failure to the plugin michael@0: if (!npp) michael@0: return -1; michael@0: michael@0: PluginDestructionGuard guard(npp); michael@0: michael@0: nsNPAPIStreamWrapper* wrapper = static_cast(pstream->ndata); michael@0: if (!wrapper) { michael@0: return -1; michael@0: } michael@0: michael@0: nsIOutputStream* stream = wrapper->GetOutputStream(); michael@0: if (!stream) { michael@0: return -1; michael@0: } michael@0: michael@0: uint32_t count = 0; michael@0: nsresult rv = stream->Write((char *)buffer, len, &count); michael@0: michael@0: if (NS_FAILED(rv)) { michael@0: return -1; michael@0: } michael@0: michael@0: return (int32_t)count; michael@0: } michael@0: michael@0: NPError michael@0: _destroystream(NPP npp, NPStream *pstream, NPError reason) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_write called from the wrong thread\n")); michael@0: return NPERR_INVALID_PARAM; michael@0: } michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, michael@0: ("NPN_DestroyStream: npp=%p, url=%s, reason=%d\n", (void*)npp, michael@0: pstream->url, (int)reason)); michael@0: michael@0: if (!npp) michael@0: return NPERR_INVALID_INSTANCE_ERROR; michael@0: michael@0: PluginDestructionGuard guard(npp); michael@0: michael@0: nsNPAPIStreamWrapper *streamWrapper = static_cast(pstream->ndata); michael@0: if (!streamWrapper) { michael@0: return NPERR_INVALID_PARAM; michael@0: } michael@0: michael@0: nsNPAPIPluginStreamListener *listener = streamWrapper->GetStreamListener(); michael@0: if (listener) { michael@0: // This type of stream is going from the browser to the plugin. It's either the michael@0: // initial src/data stream or another stream resulting from NPN_GetURL* or michael@0: // NPN_PostURL*. michael@0: // michael@0: // Calling OnStopBinding on the listener may cause it to be deleted due to the michael@0: // releasing of its last references. michael@0: listener->OnStopBinding(nullptr, NS_BINDING_ABORTED); michael@0: } else { michael@0: // This type of stream (NPStream) was created via NPN_NewStream. The plugin holds michael@0: // the reference until it is to be deleted here. Deleting the wrapper will michael@0: // release the wrapped nsIOutputStream. michael@0: // michael@0: // The NPStream the plugin references should always be a sub-object of it's own michael@0: // 'ndata', which is our nsNPAPIStramWrapper. See bug 548441. michael@0: NS_ASSERTION((char*)streamWrapper <= (char*)pstream && michael@0: ((char*)pstream) + sizeof(*pstream) michael@0: <= ((char*)streamWrapper) + sizeof(*streamWrapper), michael@0: "pstream is not a subobject of wrapper"); michael@0: delete streamWrapper; michael@0: } michael@0: michael@0: // 'listener' and/or 'streamWrapper' may be invalid (deleted) at this point. Don't michael@0: // touch them again! michael@0: michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: void michael@0: _status(NPP npp, const char *message) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_status called from the wrong thread\n")); michael@0: return; michael@0: } michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_Status: npp=%p, message=%s\n", michael@0: (void*)npp, message)); michael@0: michael@0: if (!npp || !npp->ndata) { michael@0: NS_WARNING("_status: npp or npp->ndata == 0"); michael@0: return; michael@0: } michael@0: michael@0: nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance*)npp->ndata; michael@0: michael@0: PluginDestructionGuard guard(inst); michael@0: michael@0: inst->ShowStatus(message); michael@0: } michael@0: michael@0: void michael@0: _memfree (void *ptr) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_memfree called from the wrong thread\n")); michael@0: } michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_MemFree: ptr=%p\n", ptr)); michael@0: michael@0: if (ptr) michael@0: nsMemory::Free(ptr); michael@0: } michael@0: michael@0: uint32_t michael@0: _memflush(uint32_t size) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_memflush called from the wrong thread\n")); michael@0: } michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_MemFlush: size=%d\n", size)); michael@0: michael@0: nsMemory::HeapMinimize(true); michael@0: return 0; michael@0: } michael@0: michael@0: void michael@0: _reloadplugins(NPBool reloadPages) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_reloadplugins called from the wrong thread\n")); michael@0: return; michael@0: } michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, michael@0: ("NPN_ReloadPlugins: reloadPages=%d\n", reloadPages)); michael@0: michael@0: nsCOMPtr pluginHost(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID)); michael@0: if (!pluginHost) michael@0: return; michael@0: michael@0: pluginHost->ReloadPlugins(); michael@0: } michael@0: michael@0: void michael@0: _invalidaterect(NPP npp, NPRect *invalidRect) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_invalidaterect called from the wrong thread\n")); michael@0: return; michael@0: } michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, michael@0: ("NPN_InvalidateRect: npp=%p, top=%d, left=%d, bottom=%d, " michael@0: "right=%d\n", (void *)npp, invalidRect->top, michael@0: invalidRect->left, invalidRect->bottom, invalidRect->right)); michael@0: michael@0: if (!npp || !npp->ndata) { michael@0: NS_WARNING("_invalidaterect: npp or npp->ndata == 0"); michael@0: return; michael@0: } michael@0: michael@0: nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance*)npp->ndata; michael@0: michael@0: PluginDestructionGuard guard(inst); michael@0: michael@0: inst->InvalidateRect((NPRect *)invalidRect); michael@0: } michael@0: michael@0: void michael@0: _invalidateregion(NPP npp, NPRegion invalidRegion) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_invalidateregion called from the wrong thread\n")); michael@0: return; michael@0: } michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, michael@0: ("NPN_InvalidateRegion: npp=%p, region=%p\n", (void*)npp, michael@0: (void*)invalidRegion)); michael@0: michael@0: if (!npp || !npp->ndata) { michael@0: NS_WARNING("_invalidateregion: npp or npp->ndata == 0"); michael@0: return; michael@0: } michael@0: michael@0: nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance*)npp->ndata; michael@0: michael@0: PluginDestructionGuard guard(inst); michael@0: michael@0: inst->InvalidateRegion((NPRegion)invalidRegion); michael@0: } michael@0: michael@0: void michael@0: _forceredraw(NPP npp) michael@0: { michael@0: } michael@0: michael@0: NPObject* michael@0: _getwindowobject(NPP npp) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getwindowobject called from the wrong thread\n")); michael@0: return nullptr; michael@0: } michael@0: michael@0: // The window want to return here is the outer window, *not* the inner (since michael@0: // we don't know what the plugin will do with it). michael@0: nsIDocument* doc = GetDocumentFromNPP(npp); michael@0: NS_ENSURE_TRUE(doc, nullptr); michael@0: nsCOMPtr outer = do_QueryInterface(doc->GetWindow()); michael@0: NS_ENSURE_TRUE(outer, nullptr); michael@0: michael@0: AutoJSContext cx; michael@0: JS::Rooted global(cx, static_cast(outer.get())->GetGlobalJSObject()); michael@0: return nsJSObjWrapper::GetNewOrUsed(npp, cx, global); michael@0: } michael@0: michael@0: NPObject* michael@0: _getpluginelement(NPP npp) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getpluginelement called from the wrong thread\n")); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsNPAPIPluginInstance* inst = static_cast(npp->ndata); michael@0: if (!inst) michael@0: return nullptr; michael@0: michael@0: nsCOMPtr element; michael@0: inst->GetDOMElement(getter_AddRefs(element)); michael@0: michael@0: if (!element) michael@0: return nullptr; michael@0: michael@0: AutoPushJSContext cx(GetJSContextFromNPP(npp)); michael@0: NS_ENSURE_TRUE(cx, nullptr); michael@0: JSAutoRequest ar(cx); // Unnecessary once bug 868130 lands. michael@0: michael@0: nsCOMPtr xpc(do_GetService(nsIXPConnect::GetCID())); michael@0: NS_ENSURE_TRUE(xpc, nullptr); michael@0: michael@0: nsCOMPtr holder; michael@0: xpc->WrapNative(cx, ::JS::CurrentGlobalOrNull(cx), element, michael@0: NS_GET_IID(nsIDOMElement), michael@0: getter_AddRefs(holder)); michael@0: NS_ENSURE_TRUE(holder, nullptr); michael@0: michael@0: JS::Rooted obj(cx, holder->GetJSObject()); michael@0: NS_ENSURE_TRUE(obj, nullptr); michael@0: michael@0: return nsJSObjWrapper::GetNewOrUsed(npp, cx, obj); michael@0: } michael@0: michael@0: NPIdentifier michael@0: _getstringidentifier(const NPUTF8* name) michael@0: { michael@0: if (!name) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_getstringidentifier: passed null name")); michael@0: return nullptr; michael@0: } michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getstringidentifier called from the wrong thread\n")); michael@0: } michael@0: michael@0: AutoSafeJSContext cx; michael@0: return doGetIdentifier(cx, name); michael@0: } michael@0: michael@0: void michael@0: _getstringidentifiers(const NPUTF8** names, int32_t nameCount, michael@0: NPIdentifier *identifiers) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getstringidentifiers called from the wrong thread\n")); michael@0: } michael@0: michael@0: AutoSafeJSContext cx; michael@0: michael@0: for (int32_t i = 0; i < nameCount; ++i) { michael@0: if (names[i]) { michael@0: identifiers[i] = doGetIdentifier(cx, names[i]); michael@0: } else { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_getstringidentifiers: passed null name")); michael@0: identifiers[i] = nullptr; michael@0: } michael@0: } michael@0: } michael@0: michael@0: NPIdentifier michael@0: _getintidentifier(int32_t intid) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getstringidentifier called from the wrong thread\n")); michael@0: } michael@0: return IntToNPIdentifier(intid); michael@0: } michael@0: michael@0: NPUTF8* michael@0: _utf8fromidentifier(NPIdentifier id) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_utf8fromidentifier called from the wrong thread\n")); michael@0: } michael@0: if (!id) michael@0: return nullptr; michael@0: michael@0: if (!NPIdentifierIsString(id)) { michael@0: return nullptr; michael@0: } michael@0: michael@0: JSString *str = NPIdentifierToString(id); michael@0: michael@0: return michael@0: ToNewUTF8String(nsDependentString(::JS_GetInternedStringChars(str), michael@0: ::JS_GetStringLength(str))); michael@0: } michael@0: michael@0: int32_t michael@0: _intfromidentifier(NPIdentifier id) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_intfromidentifier called from the wrong thread\n")); michael@0: } michael@0: michael@0: if (!NPIdentifierIsInt(id)) { michael@0: return INT32_MIN; michael@0: } michael@0: michael@0: return NPIdentifierToInt(id); michael@0: } michael@0: michael@0: bool michael@0: _identifierisstring(NPIdentifier id) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_identifierisstring called from the wrong thread\n")); michael@0: } michael@0: michael@0: return NPIdentifierIsString(id); michael@0: } michael@0: michael@0: NPObject* michael@0: _createobject(NPP npp, NPClass* aClass) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_createobject called from the wrong thread\n")); michael@0: return nullptr; michael@0: } michael@0: if (!npp) { michael@0: NS_ERROR("Null npp passed to _createobject()!"); michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: PluginDestructionGuard guard(npp); michael@0: michael@0: if (!aClass) { michael@0: NS_ERROR("Null class passed to _createobject()!"); michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: NPPAutoPusher nppPusher(npp); michael@0: michael@0: NPObject *npobj; michael@0: michael@0: if (aClass->allocate) { michael@0: npobj = aClass->allocate(npp, aClass); michael@0: } else { michael@0: npobj = (NPObject *)PR_Malloc(sizeof(NPObject)); michael@0: } michael@0: michael@0: if (npobj) { michael@0: npobj->_class = aClass; michael@0: npobj->referenceCount = 1; michael@0: NS_LOG_ADDREF(npobj, 1, "BrowserNPObject", sizeof(NPObject)); michael@0: } michael@0: michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, michael@0: ("Created NPObject %p, NPClass %p\n", npobj, aClass)); michael@0: michael@0: return npobj; michael@0: } michael@0: michael@0: NPObject* michael@0: _retainobject(NPObject* npobj) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_retainobject called from the wrong thread\n")); michael@0: } michael@0: if (npobj) { michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: int32_t refCnt = michael@0: #endif michael@0: PR_ATOMIC_INCREMENT((int32_t*)&npobj->referenceCount); michael@0: NS_LOG_ADDREF(npobj, refCnt, "BrowserNPObject", sizeof(NPObject)); michael@0: } michael@0: michael@0: return npobj; michael@0: } michael@0: michael@0: void michael@0: _releaseobject(NPObject* npobj) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_releaseobject called from the wrong thread\n")); michael@0: } michael@0: if (!npobj) michael@0: return; michael@0: michael@0: int32_t refCnt = PR_ATOMIC_DECREMENT((int32_t*)&npobj->referenceCount); michael@0: NS_LOG_RELEASE(npobj, refCnt, "BrowserNPObject"); michael@0: michael@0: if (refCnt == 0) { michael@0: nsNPObjWrapper::OnDestroy(npobj); michael@0: michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, michael@0: ("Deleting NPObject %p, refcount hit 0\n", npobj)); michael@0: michael@0: if (npobj->_class && npobj->_class->deallocate) { michael@0: npobj->_class->deallocate(npobj); michael@0: } else { michael@0: PR_Free(npobj); michael@0: } michael@0: } michael@0: } michael@0: michael@0: bool michael@0: _invoke(NPP npp, NPObject* npobj, NPIdentifier method, const NPVariant *args, michael@0: uint32_t argCount, NPVariant *result) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_invoke called from the wrong thread\n")); michael@0: return false; michael@0: } michael@0: if (!npp || !npobj || !npobj->_class || !npobj->_class->invoke) michael@0: return false; michael@0: michael@0: PluginDestructionGuard guard(npp); michael@0: michael@0: NPPExceptionAutoHolder nppExceptionHolder; michael@0: NPPAutoPusher nppPusher(npp); michael@0: michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, michael@0: ("NPN_Invoke(npp %p, npobj %p, method %p, args %d\n", npp, michael@0: npobj, method, argCount)); michael@0: michael@0: return npobj->_class->invoke(npobj, method, args, argCount, result); michael@0: } michael@0: michael@0: bool michael@0: _invokeDefault(NPP npp, NPObject* npobj, const NPVariant *args, michael@0: uint32_t argCount, NPVariant *result) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_invokedefault called from the wrong thread\n")); michael@0: return false; michael@0: } michael@0: if (!npp || !npobj || !npobj->_class || !npobj->_class->invokeDefault) michael@0: return false; michael@0: michael@0: NPPExceptionAutoHolder nppExceptionHolder; michael@0: NPPAutoPusher nppPusher(npp); michael@0: michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, michael@0: ("NPN_InvokeDefault(npp %p, npobj %p, args %d\n", npp, michael@0: npobj, argCount)); michael@0: michael@0: return npobj->_class->invokeDefault(npobj, args, argCount, result); michael@0: } michael@0: michael@0: bool michael@0: _evaluate(NPP npp, NPObject* npobj, NPString *script, NPVariant *result) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_evaluate called from the wrong thread\n")); michael@0: return false; michael@0: } michael@0: if (!npp) michael@0: return false; michael@0: michael@0: NPPAutoPusher nppPusher(npp); michael@0: michael@0: nsIDocument *doc = GetDocumentFromNPP(npp); michael@0: NS_ENSURE_TRUE(doc, false); michael@0: michael@0: nsGlobalWindow* win = static_cast(doc->GetInnerWindow()); michael@0: if (NS_WARN_IF(!win || !win->FastGetGlobalJSObject())) { michael@0: return false; michael@0: } michael@0: michael@0: AutoSafeJSContext cx; michael@0: JSAutoCompartment ac(cx, win->FastGetGlobalJSObject()); michael@0: michael@0: JS::Rooted obj(cx, nsNPObjWrapper::GetNewOrUsed(npp, cx, npobj)); michael@0: michael@0: if (!obj) { michael@0: return false; michael@0: } michael@0: michael@0: obj = JS_ObjectToInnerObject(cx, obj); michael@0: NS_ABORT_IF_FALSE(obj, michael@0: "JS_ObjectToInnerObject should never return null with non-null input."); michael@0: michael@0: if (result) { michael@0: // Initialize the out param to void michael@0: VOID_TO_NPVARIANT(*result); michael@0: } michael@0: michael@0: if (!script || !script->UTF8Length || !script->UTF8Characters) { michael@0: // Nothing to evaluate. michael@0: michael@0: return true; michael@0: } michael@0: michael@0: NS_ConvertUTF8toUTF16 utf16script(script->UTF8Characters, michael@0: script->UTF8Length); michael@0: michael@0: nsIPrincipal *principal = doc->NodePrincipal(); michael@0: michael@0: nsAutoCString specStr; michael@0: const char *spec; michael@0: michael@0: nsCOMPtr uri; michael@0: principal->GetURI(getter_AddRefs(uri)); michael@0: michael@0: if (uri) { michael@0: uri->GetSpec(specStr); michael@0: spec = specStr.get(); michael@0: } else { michael@0: // No URI in a principal means it's the system principal. If the michael@0: // document URI is a chrome:// URI, pass that in as the URI of the michael@0: // script, else pass in null for the filename as there's no way to michael@0: // know where this document really came from. Passing in null here michael@0: // also means that the script gets treated by XPConnect as if it michael@0: // needs additional protection, which is what we want for unknown michael@0: // chrome code anyways. michael@0: michael@0: uri = doc->GetDocumentURI(); michael@0: bool isChrome = false; michael@0: michael@0: if (uri && NS_SUCCEEDED(uri->SchemeIs("chrome", &isChrome)) && isChrome) { michael@0: uri->GetSpec(specStr); michael@0: spec = specStr.get(); michael@0: } else { michael@0: spec = nullptr; michael@0: } michael@0: } michael@0: michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, michael@0: ("NPN_Evaluate(npp %p, npobj %p, script <<<%s>>>) called\n", michael@0: npp, npobj, script->UTF8Characters)); michael@0: michael@0: JS::CompileOptions options(cx); michael@0: options.setFileAndLine(spec, 0) michael@0: .setVersion(JSVERSION_DEFAULT); michael@0: JS::Rooted rval(cx); michael@0: nsJSUtils::EvaluateOptions evalOptions; michael@0: nsresult rv = nsJSUtils::EvaluateString(cx, utf16script, obj, options, michael@0: evalOptions, &rval); michael@0: michael@0: return NS_SUCCEEDED(rv) && michael@0: (!result || JSValToNPVariant(npp, cx, rval, result)); michael@0: } michael@0: michael@0: bool michael@0: _getproperty(NPP npp, NPObject* npobj, NPIdentifier property, michael@0: NPVariant *result) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getproperty called from the wrong thread\n")); michael@0: return false; michael@0: } michael@0: if (!npp || !npobj || !npobj->_class || !npobj->_class->getProperty) michael@0: return false; michael@0: michael@0: NPPExceptionAutoHolder nppExceptionHolder; michael@0: NPPAutoPusher nppPusher(npp); michael@0: michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, michael@0: ("NPN_GetProperty(npp %p, npobj %p, property %p) called\n", michael@0: npp, npobj, property)); michael@0: michael@0: if (!npobj->_class->getProperty(npobj, property, result)) michael@0: return false; michael@0: michael@0: // If a Java plugin tries to get the document.URL or document.documentURI michael@0: // property from us, don't pass back a value that Java won't be able to michael@0: // understand -- one that will make the URL(String) constructor throw a michael@0: // MalformedURL exception. Passing such a value causes Java Plugin2 to michael@0: // crash (to throw a RuntimeException in Plugin2Manager.getDocumentBase()). michael@0: // Also don't pass back a value that Java is likely to mishandle. michael@0: michael@0: nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*) npp->ndata; michael@0: if (!inst) michael@0: return false; michael@0: nsNPAPIPlugin* plugin = inst->GetPlugin(); michael@0: if (!plugin) michael@0: return false; michael@0: nsRefPtr host = nsPluginHost::GetInst(); michael@0: nsPluginTag* pluginTag = host->TagForPlugin(plugin); michael@0: if (!pluginTag->mIsJavaPlugin) michael@0: return true; michael@0: michael@0: if (!NPVARIANT_IS_STRING(*result)) michael@0: return true; michael@0: michael@0: NPUTF8* propertyName = _utf8fromidentifier(property); michael@0: if (!propertyName) michael@0: return true; michael@0: bool notURL = michael@0: (PL_strcasecmp(propertyName, "URL") && michael@0: PL_strcasecmp(propertyName, "documentURI")); michael@0: _memfree(propertyName); michael@0: if (notURL) michael@0: return true; michael@0: michael@0: NPObject* window_obj = _getwindowobject(npp); michael@0: if (!window_obj) michael@0: return true; michael@0: michael@0: NPVariant doc_v; michael@0: NPObject* document_obj = nullptr; michael@0: NPIdentifier doc_id = _getstringidentifier("document"); michael@0: bool ok = npobj->_class->getProperty(window_obj, doc_id, &doc_v); michael@0: _releaseobject(window_obj); michael@0: if (ok) { michael@0: if (NPVARIANT_IS_OBJECT(doc_v)) { michael@0: document_obj = NPVARIANT_TO_OBJECT(doc_v); michael@0: } else { michael@0: _releasevariantvalue(&doc_v); michael@0: return true; michael@0: } michael@0: } else { michael@0: return true; michael@0: } michael@0: _releaseobject(document_obj); michael@0: if (document_obj != npobj) michael@0: return true; michael@0: michael@0: NPString urlnp = NPVARIANT_TO_STRING(*result); michael@0: nsXPIDLCString url; michael@0: url.Assign(urlnp.UTF8Characters, urlnp.UTF8Length); michael@0: michael@0: bool javaCompatible = false; michael@0: if (NS_FAILED(NS_CheckIsJavaCompatibleURLString(url, &javaCompatible))) michael@0: javaCompatible = false; michael@0: if (javaCompatible) michael@0: return true; michael@0: michael@0: // If Java won't be able to interpret the original value of document.URL or michael@0: // document.documentURI, or is likely to mishandle it, pass back something michael@0: // that Java will understand but won't be able to use to access the network, michael@0: // and for which same-origin checks will always fail. michael@0: michael@0: if (inst->mFakeURL.IsVoid()) { michael@0: // Abort (do an error return) if NS_MakeRandomInvalidURLString() fails. michael@0: if (NS_FAILED(NS_MakeRandomInvalidURLString(inst->mFakeURL))) { michael@0: _releasevariantvalue(result); michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: _releasevariantvalue(result); michael@0: char* fakeurl = (char *) _memalloc(inst->mFakeURL.Length() + 1); michael@0: strcpy(fakeurl, inst->mFakeURL); michael@0: STRINGZ_TO_NPVARIANT(fakeurl, *result); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: _setproperty(NPP npp, NPObject* npobj, NPIdentifier property, michael@0: const NPVariant *value) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_setproperty called from the wrong thread\n")); michael@0: return false; michael@0: } michael@0: if (!npp || !npobj || !npobj->_class || !npobj->_class->setProperty) michael@0: return false; michael@0: michael@0: NPPExceptionAutoHolder nppExceptionHolder; michael@0: NPPAutoPusher nppPusher(npp); michael@0: michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, michael@0: ("NPN_SetProperty(npp %p, npobj %p, property %p) called\n", michael@0: npp, npobj, property)); michael@0: michael@0: return npobj->_class->setProperty(npobj, property, value); michael@0: } michael@0: michael@0: bool michael@0: _removeproperty(NPP npp, NPObject* npobj, NPIdentifier property) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_removeproperty called from the wrong thread\n")); michael@0: return false; michael@0: } michael@0: if (!npp || !npobj || !npobj->_class || !npobj->_class->removeProperty) michael@0: return false; michael@0: michael@0: NPPExceptionAutoHolder nppExceptionHolder; michael@0: NPPAutoPusher nppPusher(npp); michael@0: michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, michael@0: ("NPN_RemoveProperty(npp %p, npobj %p, property %p) called\n", michael@0: npp, npobj, property)); michael@0: michael@0: return npobj->_class->removeProperty(npobj, property); michael@0: } michael@0: michael@0: bool michael@0: _hasproperty(NPP npp, NPObject* npobj, NPIdentifier propertyName) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_hasproperty called from the wrong thread\n")); michael@0: return false; michael@0: } michael@0: if (!npp || !npobj || !npobj->_class || !npobj->_class->hasProperty) michael@0: return false; michael@0: michael@0: NPPExceptionAutoHolder nppExceptionHolder; michael@0: NPPAutoPusher nppPusher(npp); michael@0: michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, michael@0: ("NPN_HasProperty(npp %p, npobj %p, property %p) called\n", michael@0: npp, npobj, propertyName)); michael@0: michael@0: return npobj->_class->hasProperty(npobj, propertyName); michael@0: } michael@0: michael@0: bool michael@0: _hasmethod(NPP npp, NPObject* npobj, NPIdentifier methodName) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_hasmethod called from the wrong thread\n")); michael@0: return false; michael@0: } michael@0: if (!npp || !npobj || !npobj->_class || !npobj->_class->hasMethod) michael@0: return false; michael@0: michael@0: NPPExceptionAutoHolder nppExceptionHolder; michael@0: NPPAutoPusher nppPusher(npp); michael@0: michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, michael@0: ("NPN_HasMethod(npp %p, npobj %p, property %p) called\n", michael@0: npp, npobj, methodName)); michael@0: michael@0: return npobj->_class->hasMethod(npobj, methodName); michael@0: } michael@0: michael@0: bool michael@0: _enumerate(NPP npp, NPObject *npobj, NPIdentifier **identifier, michael@0: uint32_t *count) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_enumerate called from the wrong thread\n")); michael@0: return false; michael@0: } michael@0: if (!npp || !npobj || !npobj->_class) michael@0: return false; michael@0: michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, michael@0: ("NPN_Enumerate(npp %p, npobj %p) called\n", npp, npobj)); michael@0: michael@0: if (!NP_CLASS_STRUCT_VERSION_HAS_ENUM(npobj->_class) || michael@0: !npobj->_class->enumerate) { michael@0: *identifier = 0; michael@0: *count = 0; michael@0: return true; michael@0: } michael@0: michael@0: NPPExceptionAutoHolder nppExceptionHolder; michael@0: NPPAutoPusher nppPusher(npp); michael@0: michael@0: return npobj->_class->enumerate(npobj, identifier, count); michael@0: } michael@0: michael@0: bool michael@0: _construct(NPP npp, NPObject* npobj, const NPVariant *args, michael@0: uint32_t argCount, NPVariant *result) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_construct called from the wrong thread\n")); michael@0: return false; michael@0: } michael@0: if (!npp || !npobj || !npobj->_class || michael@0: !NP_CLASS_STRUCT_VERSION_HAS_CTOR(npobj->_class) || michael@0: !npobj->_class->construct) { michael@0: return false; michael@0: } michael@0: michael@0: NPPExceptionAutoHolder nppExceptionHolder; michael@0: NPPAutoPusher nppPusher(npp); michael@0: michael@0: return npobj->_class->construct(npobj, args, argCount, result); michael@0: } michael@0: michael@0: void michael@0: _releasevariantvalue(NPVariant* variant) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_releasevariantvalue called from the wrong thread\n")); michael@0: } michael@0: switch (variant->type) { michael@0: case NPVariantType_Void : michael@0: case NPVariantType_Null : michael@0: case NPVariantType_Bool : michael@0: case NPVariantType_Int32 : michael@0: case NPVariantType_Double : michael@0: break; michael@0: case NPVariantType_String : michael@0: { michael@0: const NPString *s = &NPVARIANT_TO_STRING(*variant); michael@0: michael@0: if (s->UTF8Characters) { michael@0: #if defined(MOZ_MEMORY_WINDOWS) michael@0: if (malloc_usable_size((void *)s->UTF8Characters) != 0) { michael@0: PR_Free((void *)s->UTF8Characters); michael@0: } else { michael@0: void *p = (void *)s->UTF8Characters; michael@0: DWORD nheaps = 0; michael@0: nsAutoTArray heaps; michael@0: nheaps = GetProcessHeaps(0, heaps.Elements()); michael@0: heaps.AppendElements(nheaps); michael@0: GetProcessHeaps(nheaps, heaps.Elements()); michael@0: for (DWORD i = 0; i < nheaps; i++) { michael@0: if (InHeap(heaps[i], p)) { michael@0: HeapFree(heaps[i], 0, p); michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: #else michael@0: NS_Free((void *)s->UTF8Characters); michael@0: #endif michael@0: } michael@0: break; michael@0: } michael@0: case NPVariantType_Object: michael@0: { michael@0: NPObject *npobj = NPVARIANT_TO_OBJECT(*variant); michael@0: michael@0: if (npobj) michael@0: _releaseobject(npobj); michael@0: michael@0: break; michael@0: } michael@0: default: michael@0: NS_ERROR("Unknown NPVariant type!"); michael@0: } michael@0: michael@0: VOID_TO_NPVARIANT(*variant); michael@0: } michael@0: michael@0: void michael@0: _setexception(NPObject* npobj, const NPUTF8 *message) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_setexception called from the wrong thread\n")); michael@0: return; michael@0: } michael@0: michael@0: if (!message) return; michael@0: michael@0: if (gNPPException) { michael@0: // If a plugin throws multiple exceptions, we'll only report the michael@0: // last one for now. michael@0: free(gNPPException); michael@0: } michael@0: michael@0: gNPPException = strdup(message); michael@0: } michael@0: michael@0: NPError michael@0: _getvalue(NPP npp, NPNVariable variable, void *result) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getvalue called from the wrong thread\n")); michael@0: return NPERR_INVALID_PARAM; michael@0: } michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetValue: npp=%p, var=%d\n", michael@0: (void*)npp, (int)variable)); michael@0: michael@0: nsresult res; michael@0: michael@0: PluginDestructionGuard guard(npp); michael@0: michael@0: switch(variable) { michael@0: #if defined(XP_UNIX) && !defined(XP_MACOSX) michael@0: case NPNVxDisplay : { michael@0: #if defined(MOZ_X11) michael@0: if (npp) { michael@0: nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) npp->ndata; michael@0: bool windowless = false; michael@0: inst->IsWindowless(&windowless); michael@0: // The documentation on the types for many variables in NP(N|P)_GetValue michael@0: // is vague. Often boolean values are NPBool (1 byte), but michael@0: // https://developer.mozilla.org/en/XEmbed_Extension_for_Mozilla_Plugins michael@0: // treats NPPVpluginNeedsXEmbed as PRBool (int), and michael@0: // on x86/32-bit, flash stores to this using |movl 0x1,&needsXEmbed|. michael@0: // thus we can't use NPBool for needsXEmbed, or the three bytes above michael@0: // it on the stack would get clobbered. so protect with the larger bool. michael@0: int needsXEmbed = 0; michael@0: if (!windowless) { michael@0: res = inst->GetValueFromPlugin(NPPVpluginNeedsXEmbed, &needsXEmbed); michael@0: // If the call returned an error code make sure we still use our default value. michael@0: if (NS_FAILED(res)) { michael@0: needsXEmbed = 0; michael@0: } michael@0: } michael@0: if (windowless || needsXEmbed) { michael@0: (*(Display **)result) = mozilla::DefaultXDisplay(); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: } michael@0: #if (MOZ_WIDGET_GTK == 2) michael@0: // adobe nppdf calls XtGetApplicationNameAndClass(display, michael@0: // &instance, &class) we have to init Xt toolkit before get michael@0: // XtDisplay just call gtk_xtbin_new(w,0) once michael@0: static GtkWidget *gtkXtBinHolder = 0; michael@0: if (!gtkXtBinHolder) { michael@0: gtkXtBinHolder = gtk_xtbin_new(gdk_get_default_root_window(),0); michael@0: // it crashes on destroy, let it leak michael@0: // gtk_widget_destroy(gtkXtBinHolder); michael@0: } michael@0: (*(Display **)result) = GTK_XTBIN(gtkXtBinHolder)->xtdisplay; michael@0: return NPERR_NO_ERROR; michael@0: #endif michael@0: #endif michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: case NPNVxtAppContext: michael@0: return NPERR_GENERIC_ERROR; michael@0: #endif michael@0: michael@0: #if defined(XP_WIN) || (MOZ_WIDGET_GTK == 2) || defined(MOZ_WIDGET_QT) michael@0: case NPNVnetscapeWindow: { michael@0: if (!npp || !npp->ndata) michael@0: return NPERR_INVALID_INSTANCE_ERROR; michael@0: michael@0: nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) npp->ndata; michael@0: michael@0: nsRefPtr owner = inst->GetOwner(); michael@0: NS_ENSURE_TRUE(owner, NPERR_NO_ERROR); michael@0: michael@0: if (NS_SUCCEEDED(owner->GetNetscapeWindow(result))) { michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: #endif michael@0: michael@0: case NPNVjavascriptEnabledBool: { michael@0: *(NPBool*)result = false; michael@0: bool js = false; michael@0: res = Preferences::GetBool("javascript.enabled", &js); michael@0: if (NS_SUCCEEDED(res)) { michael@0: *(NPBool*)result = js; michael@0: } michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case NPNVasdEnabledBool: michael@0: *(NPBool*)result = false; michael@0: return NPERR_NO_ERROR; michael@0: michael@0: case NPNVisOfflineBool: { michael@0: bool offline = false; michael@0: nsCOMPtr ioservice = michael@0: do_GetService(NS_IOSERVICE_CONTRACTID, &res); michael@0: if (NS_SUCCEEDED(res)) michael@0: res = ioservice->GetOffline(&offline); michael@0: if (NS_FAILED(res)) michael@0: return NPERR_GENERIC_ERROR; michael@0: michael@0: *(NPBool*)result = offline; michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case NPNVToolkit: { michael@0: #ifdef MOZ_WIDGET_GTK michael@0: *((NPNToolkitType*)result) = NPNVGtk2; michael@0: #endif michael@0: michael@0: #ifdef MOZ_WIDGET_QT michael@0: /* Fake toolkit so flash plugin works */ michael@0: *((NPNToolkitType*)result) = NPNVGtk2; michael@0: #endif michael@0: if (*(NPNToolkitType*)result) michael@0: return NPERR_NO_ERROR; michael@0: michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: case NPNVSupportsXEmbedBool: { michael@0: #ifdef MOZ_WIDGET_GTK michael@0: *(NPBool*)result = true; michael@0: #elif defined(MOZ_WIDGET_QT) michael@0: // Desktop Flash fail to initialize if browser does not support NPNVSupportsXEmbedBool michael@0: // even when wmode!=windowed, lets return fake support michael@0: fprintf(stderr, "Fake support for XEmbed plugins in Qt port\n"); michael@0: *(NPBool*)result = true; michael@0: #else michael@0: *(NPBool*)result = false; michael@0: #endif michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case NPNVWindowNPObject: { michael@0: *(NPObject **)result = _getwindowobject(npp); michael@0: michael@0: return *(NPObject **)result ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: case NPNVPluginElementNPObject: { michael@0: *(NPObject **)result = _getpluginelement(npp); michael@0: michael@0: return *(NPObject **)result ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: case NPNVSupportsWindowless: { michael@0: #if defined(XP_WIN) || defined(XP_MACOSX) || \ michael@0: (defined(MOZ_X11) && (defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT))) michael@0: *(NPBool*)result = true; michael@0: #else michael@0: *(NPBool*)result = false; michael@0: #endif michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case NPNVprivateModeBool: { michael@0: bool privacy; michael@0: nsNPAPIPluginInstance *inst = static_cast(npp->ndata); michael@0: if (!inst) michael@0: return NPERR_GENERIC_ERROR; michael@0: michael@0: nsresult rv = inst->IsPrivateBrowsing(&privacy); michael@0: if (NS_FAILED(rv)) michael@0: return NPERR_GENERIC_ERROR; michael@0: *(NPBool*)result = (NPBool)privacy; michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case NPNVdocumentOrigin: { michael@0: nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)npp->ndata; michael@0: if (!inst) { michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: nsCOMPtr element; michael@0: inst->GetDOMElement(getter_AddRefs(element)); michael@0: if (!element) { michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: nsCOMPtr content(do_QueryInterface(element)); michael@0: if (!content) { michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: nsIPrincipal* principal = content->NodePrincipal(); michael@0: michael@0: nsAutoString utf16Origin; michael@0: res = nsContentUtils::GetUTFOrigin(principal, utf16Origin); michael@0: if (NS_FAILED(res)) { michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: nsCOMPtr normalizer = do_GetService(NS_UNICODE_NORMALIZER_CONTRACTID); michael@0: if (!normalizer) { michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: nsAutoString normalizedUTF16Origin; michael@0: res = normalizer->NormalizeUnicodeNFKC(utf16Origin, normalizedUTF16Origin); michael@0: if (NS_FAILED(res)) { michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: *(char**)result = ToNewUTF8String(normalizedUTF16Origin); michael@0: return *(char**)result ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: #ifdef XP_MACOSX michael@0: case NPNVpluginDrawingModel: { michael@0: if (npp) { michael@0: nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance*)npp->ndata; michael@0: if (inst) { michael@0: NPDrawingModel drawingModel; michael@0: inst->GetDrawingModel((int32_t*)&drawingModel); michael@0: *(NPDrawingModel*)result = drawingModel; michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: } michael@0: else { michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: } michael@0: michael@0: #ifndef NP_NO_QUICKDRAW michael@0: case NPNVsupportsQuickDrawBool: { michael@0: *(NPBool*)result = false; michael@0: michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: #endif michael@0: michael@0: case NPNVsupportsCoreGraphicsBool: { michael@0: *(NPBool*)result = true; michael@0: michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case NPNVsupportsCoreAnimationBool: { michael@0: *(NPBool*)result = nsCocoaFeatures::SupportCoreAnimationPlugins(); michael@0: michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case NPNVsupportsInvalidatingCoreAnimationBool: { michael@0: *(NPBool*)result = nsCocoaFeatures::SupportCoreAnimationPlugins(); michael@0: michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case NPNVsupportsCompositingCoreAnimationPluginsBool: { michael@0: *(NPBool*)result = PR_TRUE; michael@0: michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: #ifndef NP_NO_CARBON michael@0: case NPNVsupportsCarbonBool: { michael@0: *(NPBool*)result = false; michael@0: michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: #endif michael@0: case NPNVsupportsCocoaBool: { michael@0: *(NPBool*)result = true; michael@0: michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case NPNVsupportsUpdatedCocoaTextInputBool: { michael@0: *(NPBool*)result = true; michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case NPNVcontentsScaleFactor: { michael@0: nsNPAPIPluginInstance *inst = michael@0: (nsNPAPIPluginInstance *) (npp ? npp->ndata : nullptr); michael@0: double scaleFactor = inst ? inst->GetContentsScaleFactor() : 1.0; michael@0: *(double*)result = scaleFactor; michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: #endif michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: case kLogInterfaceV0_ANPGetValue: { michael@0: LOG("get log interface"); michael@0: ANPLogInterfaceV0 *i = (ANPLogInterfaceV0 *) result; michael@0: InitLogInterface(i); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case kBitmapInterfaceV0_ANPGetValue: { michael@0: LOG("get bitmap interface"); michael@0: ANPBitmapInterfaceV0 *i = (ANPBitmapInterfaceV0 *) result; michael@0: InitBitmapInterface(i); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case kMatrixInterfaceV0_ANPGetValue: { michael@0: LOG("get matrix interface"); michael@0: ANPMatrixInterfaceV0 *i = (ANPMatrixInterfaceV0 *) result; michael@0: InitMatrixInterface(i); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case kPathInterfaceV0_ANPGetValue: { michael@0: LOG("get path interface"); michael@0: ANPPathInterfaceV0 *i = (ANPPathInterfaceV0 *) result; michael@0: InitPathInterface(i); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case kTypefaceInterfaceV0_ANPGetValue: { michael@0: LOG("get typeface interface"); michael@0: ANPTypefaceInterfaceV0 *i = (ANPTypefaceInterfaceV0 *) result; michael@0: InitTypeFaceInterface(i); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case kPaintInterfaceV0_ANPGetValue: { michael@0: LOG("get paint interface"); michael@0: ANPPaintInterfaceV0 *i = (ANPPaintInterfaceV0 *) result; michael@0: InitPaintInterface(i); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case kCanvasInterfaceV0_ANPGetValue: { michael@0: LOG("get canvas interface"); michael@0: ANPCanvasInterfaceV0 *i = (ANPCanvasInterfaceV0 *) result; michael@0: InitCanvasInterface(i); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case kWindowInterfaceV0_ANPGetValue: { michael@0: LOG("get window interface"); michael@0: ANPWindowInterfaceV0 *i = (ANPWindowInterfaceV0 *) result; michael@0: InitWindowInterface(i); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case kAudioTrackInterfaceV0_ANPGetValue: { michael@0: LOG("get audio interface"); michael@0: ANPAudioTrackInterfaceV0 *i = (ANPAudioTrackInterfaceV0 *) result; michael@0: InitAudioTrackInterfaceV0(i); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case kEventInterfaceV0_ANPGetValue: { michael@0: LOG("get event interface"); michael@0: ANPEventInterfaceV0 *i = (ANPEventInterfaceV0 *) result; michael@0: InitEventInterface(i); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case kSystemInterfaceV0_ANPGetValue: { michael@0: LOG("get system interface"); michael@0: ANPSystemInterfaceV0* i = reinterpret_cast(result); michael@0: InitSystemInterface(i); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case kSurfaceInterfaceV0_ANPGetValue: { michael@0: LOG("get surface interface"); michael@0: ANPSurfaceInterfaceV0 *i = (ANPSurfaceInterfaceV0 *) result; michael@0: InitSurfaceInterface(i); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case kSupportedDrawingModel_ANPGetValue: { michael@0: LOG("get supported drawing model"); michael@0: uint32_t* bits = reinterpret_cast(result); michael@0: *bits = kBitmap_ANPDrawingModel && kSurface_ANPDrawingModel; michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case kJavaContext_ANPGetValue: { michael@0: jobject ret = mozilla::widget::android::GeckoAppShell::GetContext(); michael@0: if (!ret) michael@0: return NPERR_GENERIC_ERROR; michael@0: michael@0: int32_t* i = reinterpret_cast(result); michael@0: *i = reinterpret_cast(ret); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case kAudioTrackInterfaceV1_ANPGetValue: { michael@0: LOG("get audio interface v1"); michael@0: ANPAudioTrackInterfaceV1 *i = (ANPAudioTrackInterfaceV1 *) result; michael@0: InitAudioTrackInterfaceV1(i); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case kNativeWindowInterfaceV0_ANPGetValue: { michael@0: LOG("get native window interface v0"); michael@0: ANPNativeWindowInterfaceV0* i = (ANPNativeWindowInterfaceV0 *) result; michael@0: InitNativeWindowInterface(i); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case kOpenGLInterfaceV0_ANPGetValue: { michael@0: LOG("get openGL interface"); michael@0: ANPOpenGLInterfaceV0 *i = (ANPOpenGLInterfaceV0*) result; michael@0: InitOpenGLInterface(i); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case kWindowInterfaceV1_ANPGetValue: { michael@0: LOG("get Window interface V1"); michael@0: ANPWindowInterfaceV1 *i = (ANPWindowInterfaceV1 *) result; michael@0: InitWindowInterfaceV1(i); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case kWindowInterfaceV2_ANPGetValue: { michael@0: LOG("get Window interface V2"); michael@0: ANPWindowInterfaceV2 *i = (ANPWindowInterfaceV2 *) result; michael@0: InitWindowInterfaceV2(i); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case kVideoInterfaceV0_ANPGetValue: { michael@0: LOG("get video interface"); michael@0: ANPVideoInterfaceV0 *i = (ANPVideoInterfaceV0*) result; michael@0: InitVideoInterfaceV0(i); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case kVideoInterfaceV1_ANPGetValue: { michael@0: LOG("get video interface"); michael@0: ANPVideoInterfaceV1 *i = (ANPVideoInterfaceV1*) result; michael@0: InitVideoInterfaceV1(i); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: michael@0: case kSystemInterfaceV1_ANPGetValue: { michael@0: LOG("get system interface v1"); michael@0: ANPSystemInterfaceV1* i = reinterpret_cast(result); michael@0: InitSystemInterfaceV1(i); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case kSystemInterfaceV2_ANPGetValue: { michael@0: LOG("get system interface v2"); michael@0: ANPSystemInterfaceV2* i = reinterpret_cast(result); michael@0: InitSystemInterfaceV2(i); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: #endif michael@0: michael@0: // we no longer hand out any XPCOM objects michael@0: case NPNVDOMElement: michael@0: // fall through michael@0: case NPNVDOMWindow: michael@0: // fall through michael@0: case NPNVserviceManager: michael@0: // old XPCOM objects, no longer supported, but null out the out michael@0: // param to avoid crashing plugins that still try to use this. michael@0: *(nsISupports**)result = nullptr; michael@0: // fall through michael@0: default: michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_getvalue unhandled get value: %d\n", variable)); michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: } michael@0: michael@0: NPError michael@0: _setvalue(NPP npp, NPPVariable variable, void *result) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_setvalue called from the wrong thread\n")); michael@0: return NPERR_INVALID_PARAM; michael@0: } michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_SetValue: npp=%p, var=%d\n", michael@0: (void*)npp, (int)variable)); michael@0: michael@0: if (!npp) michael@0: return NPERR_INVALID_INSTANCE_ERROR; michael@0: michael@0: nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) npp->ndata; michael@0: michael@0: NS_ASSERTION(inst, "null instance"); michael@0: michael@0: if (!inst) michael@0: return NPERR_INVALID_INSTANCE_ERROR; michael@0: michael@0: PluginDestructionGuard guard(inst); michael@0: michael@0: switch (variable) { michael@0: michael@0: // we should keep backward compatibility with NPAPI where the michael@0: // actual pointer value is checked rather than its content michael@0: // when passing booleans michael@0: case NPPVpluginWindowBool: { michael@0: #ifdef XP_MACOSX michael@0: // This setting doesn't apply to OS X (only to Windows and Unix/Linux). michael@0: // See https://developer.mozilla.org/En/NPN_SetValue#section_5. Return michael@0: // NPERR_NO_ERROR here to conform to other browsers' behavior on OS X michael@0: // (e.g. Safari and Opera). michael@0: return NPERR_NO_ERROR; michael@0: #else michael@0: NPBool bWindowless = (result == nullptr); michael@0: return inst->SetWindowless(bWindowless); michael@0: #endif michael@0: } michael@0: case NPPVpluginTransparentBool: { michael@0: NPBool bTransparent = (result != nullptr); michael@0: return inst->SetTransparent(bTransparent); michael@0: } michael@0: michael@0: case NPPVjavascriptPushCallerBool: { michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case NPPVpluginKeepLibraryInMemory: { michael@0: NPBool bCached = (result != nullptr); michael@0: inst->SetCached(bCached); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case NPPVpluginUsesDOMForCursorBool: { michael@0: bool useDOMForCursor = (result != nullptr); michael@0: return inst->SetUsesDOMForCursor(useDOMForCursor); michael@0: } michael@0: michael@0: #ifndef MOZ_WIDGET_ANDROID michael@0: // On android, their 'drawing model' uses the same constant! michael@0: case NPPVpluginDrawingModel: { michael@0: if (inst) { michael@0: inst->SetDrawingModel((NPDrawingModel)NS_PTR_TO_INT32(result)); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: else { michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: #ifdef XP_MACOSX michael@0: case NPPVpluginEventModel: { michael@0: if (inst) { michael@0: inst->SetEventModel((NPEventModel)NS_PTR_TO_INT32(result)); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: else { michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: } michael@0: #endif michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: case kRequestDrawingModel_ANPSetValue: michael@0: if (inst) michael@0: inst->SetANPDrawingModel(NS_PTR_TO_INT32(result)); michael@0: return NPERR_NO_ERROR; michael@0: case kAcceptEvents_ANPSetValue: michael@0: return NPERR_NO_ERROR; michael@0: #endif michael@0: default: michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: } michael@0: michael@0: NPError michael@0: _requestread(NPStream *pstream, NPByteRange *rangeList) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_requestread called from the wrong thread\n")); michael@0: return NPERR_INVALID_PARAM; michael@0: } michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_RequestRead: stream=%p\n", michael@0: (void*)pstream)); michael@0: michael@0: #ifdef PLUGIN_LOGGING michael@0: for(NPByteRange * range = rangeList; range != nullptr; range = range->next) michael@0: PR_LOG(nsPluginLogging::gNPNLog,PLUGIN_LOG_NOISY, michael@0: ("%i-%i", range->offset, range->offset + range->length - 1)); michael@0: michael@0: PR_LOG(nsPluginLogging::gNPNLog,PLUGIN_LOG_NOISY, ("\n\n")); michael@0: PR_LogFlush(); michael@0: #endif michael@0: michael@0: if (!pstream || !rangeList || !pstream->ndata) michael@0: return NPERR_INVALID_PARAM; michael@0: michael@0: nsNPAPIStreamWrapper* streamWrapper = static_cast(pstream->ndata); michael@0: nsNPAPIPluginStreamListener* streamlistener = streamWrapper->GetStreamListener(); michael@0: if (!streamlistener) { michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: int32_t streamtype = NP_NORMAL; michael@0: michael@0: streamlistener->GetStreamType(&streamtype); michael@0: michael@0: if (streamtype != NP_SEEK) michael@0: return NPERR_STREAM_NOT_SEEKABLE; michael@0: michael@0: if (!streamlistener->mStreamListenerPeer) michael@0: return NPERR_GENERIC_ERROR; michael@0: michael@0: nsresult rv = streamlistener->mStreamListenerPeer->RequestRead((NPByteRange *)rangeList); michael@0: if (NS_FAILED(rv)) michael@0: return NPERR_GENERIC_ERROR; michael@0: michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: // Deprecated, only stubbed out michael@0: void* /* OJI type: JRIEnv* */ michael@0: _getJavaEnv() michael@0: { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetJavaEnv\n")); michael@0: return nullptr; michael@0: } michael@0: michael@0: const char * michael@0: _useragent(NPP npp) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_useragent called from the wrong thread\n")); michael@0: return nullptr; michael@0: } michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_UserAgent: npp=%p\n", (void*)npp)); michael@0: michael@0: nsCOMPtr pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID)); michael@0: nsPluginHost *pluginHost = static_cast(pluginHostCOM.get()); michael@0: if (!pluginHost) { michael@0: return nullptr; michael@0: } michael@0: michael@0: const char *retstr; michael@0: nsresult rv = pluginHost->UserAgent(&retstr); michael@0: if (NS_FAILED(rv)) michael@0: return nullptr; michael@0: michael@0: return retstr; michael@0: } michael@0: michael@0: void * michael@0: _memalloc (uint32_t size) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,("NPN_memalloc called from the wrong thread\n")); michael@0: } michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_MemAlloc: size=%d\n", size)); michael@0: return nsMemory::Alloc(size); michael@0: } michael@0: michael@0: // Deprecated, only stubbed out michael@0: void* /* OJI type: jref */ michael@0: _getJavaPeer(NPP npp) michael@0: { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetJavaPeer: npp=%p\n", (void*)npp)); michael@0: return nullptr; michael@0: } michael@0: michael@0: void michael@0: _pushpopupsenabledstate(NPP npp, NPBool enabled) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_pushpopupsenabledstate called from the wrong thread\n")); michael@0: return; michael@0: } michael@0: nsNPAPIPluginInstance *inst = npp ? (nsNPAPIPluginInstance *)npp->ndata : nullptr; michael@0: if (!inst) michael@0: return; michael@0: michael@0: inst->PushPopupsEnabledState(enabled); michael@0: } michael@0: michael@0: void michael@0: _poppopupsenabledstate(NPP npp) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_poppopupsenabledstate called from the wrong thread\n")); michael@0: return; michael@0: } michael@0: nsNPAPIPluginInstance *inst = npp ? (nsNPAPIPluginInstance *)npp->ndata : nullptr; michael@0: if (!inst) michael@0: return; michael@0: michael@0: inst->PopPopupsEnabledState(); michael@0: } michael@0: michael@0: void michael@0: _pluginthreadasynccall(NPP instance, PluginThreadCallback func, void *userData) michael@0: { michael@0: if (NS_IsMainThread()) { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,("NPN_pluginthreadasynccall called from the main thread\n")); michael@0: } else { michael@0: NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,("NPN_pluginthreadasynccall called from a non main thread\n")); michael@0: } michael@0: nsRefPtr evt = michael@0: new nsPluginThreadRunnable(instance, func, userData); michael@0: michael@0: if (evt && evt->IsValid()) { michael@0: NS_DispatchToMainThread(evt); michael@0: } michael@0: } michael@0: michael@0: NPError michael@0: _getvalueforurl(NPP instance, NPNURLVariable variable, const char *url, michael@0: char **value, uint32_t *len) michael@0: { michael@0: if (!instance) { michael@0: return NPERR_INVALID_PARAM; michael@0: } michael@0: michael@0: if (!url || !*url || !len) { michael@0: return NPERR_INVALID_URL; michael@0: } michael@0: michael@0: *len = 0; michael@0: michael@0: switch (variable) { michael@0: case NPNURLVProxy: michael@0: { michael@0: nsCOMPtr pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID)); michael@0: nsPluginHost *pluginHost = static_cast(pluginHostCOM.get()); michael@0: if (pluginHost && NS_SUCCEEDED(pluginHost->FindProxyForURL(url, value))) { michael@0: *len = *value ? strlen(*value) : 0; michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: break; michael@0: } michael@0: case NPNURLVCookie: michael@0: { michael@0: nsCOMPtr cookieService = michael@0: do_GetService(NS_COOKIESERVICE_CONTRACTID); michael@0: michael@0: if (!cookieService) michael@0: return NPERR_GENERIC_ERROR; michael@0: michael@0: // Make an nsURI from the url argument michael@0: nsCOMPtr uri; michael@0: if (NS_FAILED(NS_NewURI(getter_AddRefs(uri), nsDependentCString(url)))) { michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: nsCOMPtr channel = GetChannelFromNPP(instance); michael@0: michael@0: if (NS_FAILED(cookieService->GetCookieString(uri, channel, value)) || michael@0: !*value) { michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: *len = strlen(*value); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: break; michael@0: default: michael@0: // Fall through and return an error... michael@0: ; michael@0: } michael@0: michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: NPError michael@0: _setvalueforurl(NPP instance, NPNURLVariable variable, const char *url, michael@0: const char *value, uint32_t len) michael@0: { michael@0: if (!instance) { michael@0: return NPERR_INVALID_PARAM; michael@0: } michael@0: michael@0: if (!url || !*url) { michael@0: return NPERR_INVALID_URL; michael@0: } michael@0: michael@0: switch (variable) { michael@0: case NPNURLVCookie: michael@0: { michael@0: if (!url || !value || (0 >= len)) michael@0: return NPERR_INVALID_PARAM; michael@0: michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: nsCOMPtr ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv)); michael@0: if (NS_FAILED(rv)) michael@0: return NPERR_GENERIC_ERROR; michael@0: michael@0: nsCOMPtr cookieService = do_GetService(NS_COOKIESERVICE_CONTRACTID, &rv); michael@0: if (NS_FAILED(rv)) michael@0: return NPERR_GENERIC_ERROR; michael@0: michael@0: nsCOMPtr uriIn; michael@0: rv = ioService->NewURI(nsDependentCString(url), nullptr, nullptr, getter_AddRefs(uriIn)); michael@0: if (NS_FAILED(rv)) michael@0: return NPERR_GENERIC_ERROR; michael@0: michael@0: nsCOMPtr channel = GetChannelFromNPP(instance); michael@0: michael@0: char *cookie = (char*)value; michael@0: char c = cookie[len]; michael@0: cookie[len] = '\0'; michael@0: rv = cookieService->SetCookieString(uriIn, nullptr, cookie, channel); michael@0: cookie[len] = c; michael@0: if (NS_SUCCEEDED(rv)) michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: break; michael@0: case NPNURLVProxy: michael@0: // We don't support setting proxy values, fall through... michael@0: default: michael@0: // Fall through and return an error... michael@0: ; michael@0: } michael@0: michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: NPError michael@0: _getauthenticationinfo(NPP instance, const char *protocol, const char *host, michael@0: int32_t port, const char *scheme, const char *realm, michael@0: char **username, uint32_t *ulen, char **password, michael@0: uint32_t *plen) michael@0: { michael@0: if (!instance || !protocol || !host || !scheme || !realm || !username || michael@0: !ulen || !password || !plen) michael@0: return NPERR_INVALID_PARAM; michael@0: michael@0: *username = nullptr; michael@0: *password = nullptr; michael@0: *ulen = 0; michael@0: *plen = 0; michael@0: michael@0: nsDependentCString proto(protocol); michael@0: michael@0: if (!proto.LowerCaseEqualsLiteral("http") && michael@0: !proto.LowerCaseEqualsLiteral("https")) michael@0: return NPERR_GENERIC_ERROR; michael@0: michael@0: nsCOMPtr authManager = michael@0: do_GetService("@mozilla.org/network/http-auth-manager;1"); michael@0: if (!authManager) michael@0: return NPERR_GENERIC_ERROR; michael@0: michael@0: nsNPAPIPluginInstance *inst = static_cast(instance->ndata); michael@0: if (!inst) michael@0: return NPERR_GENERIC_ERROR; michael@0: michael@0: bool authPrivate = false; michael@0: if (NS_FAILED(inst->IsPrivateBrowsing(&authPrivate))) michael@0: return NPERR_GENERIC_ERROR; michael@0: michael@0: nsIDocument *doc = GetDocumentFromNPP(instance); michael@0: NS_ENSURE_TRUE(doc, NPERR_GENERIC_ERROR); michael@0: nsIPrincipal *principal = doc->NodePrincipal(); michael@0: michael@0: nsAutoString unused, uname16, pwd16; michael@0: if (NS_FAILED(authManager->GetAuthIdentity(proto, nsDependentCString(host), michael@0: port, nsDependentCString(scheme), michael@0: nsDependentCString(realm), michael@0: EmptyCString(), unused, uname16, michael@0: pwd16, authPrivate, principal))) { michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: NS_ConvertUTF16toUTF8 uname8(uname16); michael@0: NS_ConvertUTF16toUTF8 pwd8(pwd16); michael@0: michael@0: *username = ToNewCString(uname8); michael@0: *ulen = *username ? uname8.Length() : 0; michael@0: michael@0: *password = ToNewCString(pwd8); michael@0: *plen = *password ? pwd8.Length() : 0; michael@0: michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: uint32_t michael@0: _scheduletimer(NPP instance, uint32_t interval, NPBool repeat, PluginTimerFunc timerFunc) michael@0: { michael@0: nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata; michael@0: if (!inst) michael@0: return 0; michael@0: michael@0: return inst->ScheduleTimer(interval, repeat, timerFunc); michael@0: } michael@0: michael@0: void michael@0: _unscheduletimer(NPP instance, uint32_t timerID) michael@0: { michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: // Sometimes Flash calls this with a dead NPP instance. Ensure the one we have michael@0: // here is valid and maps to a nsNPAPIPluginInstance. michael@0: nsNPAPIPluginInstance *inst = nsNPAPIPluginInstance::GetFromNPP(instance); michael@0: #else michael@0: nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata; michael@0: #endif michael@0: if (!inst) michael@0: return; michael@0: michael@0: inst->UnscheduleTimer(timerID); michael@0: } michael@0: michael@0: NPError michael@0: _popupcontextmenu(NPP instance, NPMenu* menu) michael@0: { michael@0: nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata; michael@0: if (!inst) michael@0: return NPERR_GENERIC_ERROR; michael@0: michael@0: return inst->PopUpContextMenu(menu); michael@0: } michael@0: michael@0: NPError michael@0: _initasyncsurface(NPP instance, NPSize *size, NPImageFormat format, void *initData, NPAsyncSurface *surface) michael@0: { michael@0: nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata; michael@0: if (!inst) michael@0: return NPERR_GENERIC_ERROR; michael@0: michael@0: return inst->InitAsyncSurface(size, format, initData, surface); michael@0: } michael@0: michael@0: NPError michael@0: _finalizeasyncsurface(NPP instance, NPAsyncSurface *surface) michael@0: { michael@0: nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata; michael@0: if (!inst) michael@0: return NPERR_GENERIC_ERROR; michael@0: michael@0: return inst->FinalizeAsyncSurface(surface); michael@0: } michael@0: michael@0: void michael@0: _setcurrentasyncsurface(NPP instance, NPAsyncSurface *surface, NPRect *changed) michael@0: { michael@0: nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata; michael@0: if (!inst) michael@0: return; michael@0: michael@0: inst->SetCurrentAsyncSurface(surface, changed); michael@0: } michael@0: michael@0: NPBool michael@0: _convertpoint(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace) michael@0: { michael@0: nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata; michael@0: if (!inst) michael@0: return false; michael@0: michael@0: return inst->ConvertPoint(sourceX, sourceY, sourceSpace, destX, destY, destSpace); michael@0: } michael@0: michael@0: void michael@0: _urlredirectresponse(NPP instance, void* notifyData, NPBool allow) michael@0: { michael@0: nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata; michael@0: if (!inst) { michael@0: return; michael@0: } michael@0: michael@0: inst->URLRedirectResponse(notifyData, allow); michael@0: } michael@0: michael@0: } /* namespace parent */ michael@0: } /* namespace plugins */ michael@0: } /* namespace mozilla */