/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "base/basictypes.h" /* This must occur *after* layers/PLayerTransaction.h to avoid typedefs * conflicts. */ #include "mozilla/ArrayUtils.h" #include "pratom.h" #include "prenv.h" #include "jsfriendapi.h" #include "js/friend/WindowProxy.h" // js::ToWindowIfWindowProxy #include "js/Object.h" // JS::GetCompartment #include "nsPluginHost.h" #include "nsNPAPIPlugin.h" #include "nsNPAPIPluginInstance.h" #include "nsNPAPIPluginStreamListener.h" #include "nsPluginStreamListenerPeer.h" #include "nsThreadUtils.h" #include "mozilla/CycleCollectedJSContext.h" // for nsAutoMicroTask #include "mozilla/Preferences.h" #include "nsPluginInstanceOwner.h" #include "nsPluginsDir.h" #include "nsPluginLogging.h" #include "nsPIDOMWindow.h" #include "nsGlobalWindow.h" #include "mozilla/dom/Document.h" #include "nsIContent.h" #include "nsIIDNService.h" #include "nsIScriptGlobalObject.h" #include "nsIScriptContext.h" #include "nsDOMJSUtils.h" #include "nsIPrincipal.h" #include "nsWildCard.h" #include "nsContentUtils.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/JSExecutionContext.h" #include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/ToJSValue.h" #include "nsIXPConnect.h" #include "nsMemory.h" #include #ifdef MOZ_WIDGET_COCOA # include # include # include # include "nsCocoaFeatures.h" # include "PluginUtilsOSX.h" #endif // needed for nppdf plugin #if (MOZ_WIDGET_GTK) # include # include #endif #include "nsJSUtils.h" #include "nsJSNPRuntime.h" #include "nsNetUtil.h" #include "nsNetCID.h" #include "mozilla/Mutex.h" #include "mozilla/PluginLibrary.h" using mozilla::PluginLibrary; #include "mozilla/plugins/PluginModuleParent.h" using mozilla::plugins::PluginModuleChromeParent; using mozilla::plugins::PluginModuleContentParent; #ifdef MOZ_X11 # include "mozilla/X11Util.h" #endif #ifdef XP_WIN # include # include "mozilla/WindowsVersion.h" # ifdef ACCESSIBILITY # include "mozilla/a11y/Compatibility.h" # endif #endif #include "AudioChannelService.h" using namespace mozilla; using namespace mozilla::plugins::parent; using mozilla::dom::Document; using mozilla::dom::JSExecutionContext; // We should make this const... static NPNetscapeFuncs sBrowserFuncs = { sizeof(sBrowserFuncs), (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR, _geturl, _posturl, _requestread, nullptr, // _newstream, unimplemented nullptr, // _write, unimplemented nullptr, // _destroystream, unimplemented _status, _useragent, _memalloc, _memfree, _memflush, _reloadplugins, _getJavaEnv, _getJavaPeer, _geturlnotify, _posturlnotify, _getvalue, _setvalue, _invalidaterect, _invalidateregion, _forceredraw, _getstringidentifier, _getstringidentifiers, _getintidentifier, _identifierisstring, _utf8fromidentifier, _intfromidentifier, _createobject, _retainobject, _releaseobject, _invoke, _invokeDefault, _evaluate, _getproperty, _setproperty, _removeproperty, _hasproperty, _hasmethod, _releasevariantvalue, _setexception, _pushpopupsenabledstate, _poppopupsenabledstate, _enumerate, nullptr, // pluginthreadasynccall, not used _construct, _getvalueforurl, _setvalueforurl, nullptr, // NPN GetAuthenticationInfo, not supported _scheduletimer, _unscheduletimer, _popupcontextmenu, _convertpoint, nullptr, // handleevent, unimplemented nullptr, // unfocusinstance, unimplemented _urlredirectresponse, _initasyncsurface, _finalizeasyncsurface, _setcurrentasyncsurface}; // POST/GET stream type enum eNPPStreamTypeInternal { eNPPStreamTypeInternal_Get, eNPPStreamTypeInternal_Post }; void NS_NotifyBeginPluginCall(NSPluginCallReentry aReentryState) { nsNPAPIPluginInstance::BeginPluginCall(aReentryState); } void NS_NotifyPluginCall(NSPluginCallReentry aReentryState) { nsNPAPIPluginInstance::EndPluginCall(aReentryState); } nsNPAPIPlugin::nsNPAPIPlugin() { memset((void*)&mPluginFuncs, 0, sizeof(mPluginFuncs)); mPluginFuncs.size = sizeof(mPluginFuncs); mPluginFuncs.version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR; mLibrary = nullptr; } nsNPAPIPlugin::~nsNPAPIPlugin() { delete mLibrary; mLibrary = nullptr; } void nsNPAPIPlugin::PluginCrashed(const nsAString& aPluginDumpID, const nsACString& aAdditionalMinidumps) { RefPtr host = nsPluginHost::GetInst(); host->PluginCrashed(this, aPluginDumpID, aAdditionalMinidumps); } inline PluginLibrary* GetNewPluginLibrary(nsPluginTag* aPluginTag) { AUTO_PROFILER_LABEL("GetNewPluginLibrary", OTHER); if (!aPluginTag) { return nullptr; } if (XRE_IsContentProcess()) { return PluginModuleContentParent::LoadModule(aPluginTag->mId, aPluginTag); } return PluginModuleChromeParent::LoadModule(aPluginTag->mFullPath.get(), aPluginTag->mId, aPluginTag); } // Creates an nsNPAPIPlugin object. One nsNPAPIPlugin object exists per plugin // (not instance). nsresult nsNPAPIPlugin::CreatePlugin(nsPluginTag* aPluginTag, nsNPAPIPlugin** aResult) { AUTO_PROFILER_LABEL("nsNPAPIPlugin::CreatePlugin", OTHER); *aResult = nullptr; if (!aPluginTag) { return NS_ERROR_FAILURE; } RefPtr plugin = new nsNPAPIPlugin(); PluginLibrary* pluginLib = GetNewPluginLibrary(aPluginTag); if (!pluginLib) { return NS_ERROR_FAILURE; } #if defined(XP_MACOSX) if (!pluginLib->HasRequiredFunctions()) { NS_WARNING( "Not all necessary functions exposed by plugin, it will not load."); delete pluginLib; return NS_ERROR_FAILURE; } #endif plugin->mLibrary = pluginLib; pluginLib->SetPlugin(plugin); // Exchange NPAPI entry points. #if defined(XP_WIN) // NP_GetEntryPoints must be called before NP_Initialize on Windows. NPError pluginCallError; nsresult rv = pluginLib->NP_GetEntryPoints(&plugin->mPluginFuncs, &pluginCallError); if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) { return NS_ERROR_FAILURE; } // NP_Initialize must be called after NP_GetEntryPoints on Windows. rv = pluginLib->NP_Initialize(&sBrowserFuncs, &pluginCallError); if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) { return NS_ERROR_FAILURE; } #elif defined(XP_MACOSX) // NP_Initialize must be called before NP_GetEntryPoints on Mac OS X. // We need to match WebKit's behavior. NPError pluginCallError; nsresult rv = pluginLib->NP_Initialize(&sBrowserFuncs, &pluginCallError); if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) { return NS_ERROR_FAILURE; } rv = pluginLib->NP_GetEntryPoints(&plugin->mPluginFuncs, &pluginCallError); if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) { return NS_ERROR_FAILURE; } #else NPError pluginCallError; nsresult rv = pluginLib->NP_Initialize(&sBrowserFuncs, &plugin->mPluginFuncs, &pluginCallError); if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) { return NS_ERROR_FAILURE; } #endif plugin.forget(aResult); return NS_OK; } PluginLibrary* nsNPAPIPlugin::GetLibrary() { return mLibrary; } NPPluginFuncs* nsNPAPIPlugin::PluginFuncs() { return &mPluginFuncs; } nsresult nsNPAPIPlugin::Shutdown() { NPP_PLUGIN_LOG(PLUGIN_LOG_BASIC, ("NPP Shutdown to be called: this=%p\n", this)); NPError shutdownError; mLibrary->NP_Shutdown(&shutdownError); return NS_OK; } nsresult nsNPAPIPlugin::RetainStream(NPStream* pstream, nsISupports** aRetainedPeer) { if (!aRetainedPeer) return NS_ERROR_NULL_POINTER; *aRetainedPeer = nullptr; if (!pstream || !pstream->ndata) return NS_ERROR_NULL_POINTER; nsNPAPIStreamWrapper* streamWrapper = static_cast(pstream->ndata); nsNPAPIPluginStreamListener* listener = streamWrapper->GetStreamListener(); if (!listener) { return NS_ERROR_NULL_POINTER; } nsIStreamListener* streamListener = listener->GetStreamListenerPeer(); if (!streamListener) { return NS_ERROR_NULL_POINTER; } *aRetainedPeer = streamListener; NS_ADDREF(*aRetainedPeer); return NS_OK; } // Create a new NPP GET or POST (given in the type argument) url // stream that may have a notify callback NPError MakeNewNPAPIStreamInternal(NPP npp, const char* relativeURL, const char* target, eNPPStreamTypeInternal type, bool bDoNotify = false, void* notifyData = nullptr, uint32_t len = 0, const char* buf = nullptr) { if (!npp) return NPERR_INVALID_INSTANCE_ERROR; PluginDestructionGuard guard(npp); nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)npp->ndata; if (!inst || !inst->IsRunning()) return NPERR_INVALID_INSTANCE_ERROR; nsCOMPtr pluginHostCOM = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID); nsPluginHost* pluginHost = static_cast(pluginHostCOM.get()); if (!pluginHost) { return NPERR_GENERIC_ERROR; } RefPtr listener; // Set aCallNotify here to false. If pluginHost->GetURL or PostURL fail, // the listener's destructor will do the notification while we are about to // return a failure code. // Call SetCallNotify(true) below after we are sure we cannot return a failure // code. if (!target) { inst->NewStreamListener(relativeURL, notifyData, getter_AddRefs(listener)); if (listener) { listener->SetCallNotify(false); } } switch (type) { case eNPPStreamTypeInternal_Get: { if (NS_FAILED(pluginHost->GetURL(inst, relativeURL, target, listener, nullptr, nullptr, false))) return NPERR_GENERIC_ERROR; break; } case eNPPStreamTypeInternal_Post: { if (NS_FAILED(pluginHost->PostURL(inst, relativeURL, len, buf, target, listener, nullptr, nullptr, false, 0, nullptr))) return NPERR_GENERIC_ERROR; break; } default: NS_ERROR("how'd I get here"); } if (listener) { // SetCallNotify(bDoNotify) here, see comment above. listener->SetCallNotify(bDoNotify); } return NPERR_NO_ERROR; } #if defined(MOZ_MEMORY) && defined(XP_WIN) extern "C" size_t malloc_usable_size(const void* ptr); #endif namespace { static char* gNPPException; static Document* GetDocumentFromNPP(NPP npp) { NS_ENSURE_TRUE(npp, nullptr); nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)npp->ndata; NS_ENSURE_TRUE(inst, nullptr); PluginDestructionGuard guard(inst); RefPtr owner = inst->GetOwner(); NS_ENSURE_TRUE(owner, nullptr); nsCOMPtr doc; owner->GetDocument(getter_AddRefs(doc)); return doc; } static NPIdentifier doGetIdentifier(JSContext* cx, const NPUTF8* name) { NS_ConvertUTF8toUTF16 utf16name(name); JSString* str = ::JS_AtomizeAndPinUCStringN(cx, utf16name.get(), utf16name.Length()); if (!str) return nullptr; return StringToNPIdentifier(cx, str); } #if defined(MOZ_MEMORY) && defined(XP_WIN) BOOL InHeap(HANDLE hHeap, LPVOID lpMem) { BOOL success = FALSE; PROCESS_HEAP_ENTRY he; he.lpData = nullptr; while (HeapWalk(hHeap, &he) != 0) { if (he.lpData == lpMem) { success = TRUE; break; } } HeapUnlock(hHeap); return success; } #endif } /* anonymous namespace */ NPPExceptionAutoHolder::NPPExceptionAutoHolder() : mOldException(gNPPException) { gNPPException = nullptr; } NPPExceptionAutoHolder::~NPPExceptionAutoHolder() { NS_ASSERTION(!gNPPException, "NPP exception not properly cleared!"); gNPPException = mOldException; } NPP NPPStack::sCurrentNPP = nullptr; const char* PeekException() { return gNPPException; } void PopException() { NS_ASSERTION(gNPPException, "Uh, no NPP exception to pop!"); if (gNPPException) { free(gNPPException); gNPPException = nullptr; } } // // Static callbacks that get routed back through the new C++ API // namespace mozilla::plugins::parent { NPError _geturl(NPP npp, const char* relativeURL, const char* target) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_geturl called from the wrong thread\n")); return NPERR_INVALID_PARAM; } NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetURL: npp=%p, target=%s, url=%s\n", (void*)npp, target, relativeURL)); PluginDestructionGuard guard(npp); return MakeNewNPAPIStreamInternal(npp, relativeURL, target, eNPPStreamTypeInternal_Get); } NPError _geturlnotify(NPP npp, const char* relativeURL, const char* target, void* notifyData) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_geturlnotify called from the wrong thread\n")); return NPERR_INVALID_PARAM; } NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetURLNotify: npp=%p, target=%s, notify=%p, url=%s\n", (void*)npp, target, notifyData, relativeURL)); PluginDestructionGuard guard(npp); return MakeNewNPAPIStreamInternal( npp, relativeURL, target, eNPPStreamTypeInternal_Get, true, notifyData); } NPError _posturlnotify(NPP npp, const char* relativeURL, const char* target, uint32_t len, const char* buf, NPBool file, void* notifyData) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_posturlnotify called from the wrong thread\n")); return NPERR_INVALID_PARAM; } if (!buf) return NPERR_INVALID_PARAM; NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_PostURLNotify: npp=%p, target=%s, len=%d, file=%d, " "notify=%p, url=%s, buf=%s\n", (void*)npp, target, len, file, notifyData, relativeURL, buf)); PluginDestructionGuard guard(npp); return MakeNewNPAPIStreamInternal(npp, relativeURL, target, eNPPStreamTypeInternal_Post, true, notifyData, len, buf); } NPError _posturl(NPP npp, const char* relativeURL, const char* target, uint32_t len, const char* buf, NPBool file) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_posturl called from the wrong thread\n")); return NPERR_INVALID_PARAM; } NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_PostURL: npp=%p, target=%s, file=%d, len=%d, url=%s, " "buf=%s\n", (void*)npp, target, file, len, relativeURL, buf)); PluginDestructionGuard guard(npp); return MakeNewNPAPIStreamInternal(npp, relativeURL, target, eNPPStreamTypeInternal_Post, false, nullptr, len, buf); } void _status(NPP npp, const char* message) { // NPN_Status is no longer supported. } void _memfree(void* ptr) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_memfree called from the wrong thread\n")); } NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_MemFree: ptr=%p\n", ptr)); if (ptr) free(ptr); } uint32_t _memflush(uint32_t size) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_memflush called from the wrong thread\n")); } NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_MemFlush: size=%d\n", size)); nsMemory::HeapMinimize(true); return 0; } void _reloadplugins(NPBool reloadPages) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_reloadplugins called from the wrong thread\n")); return; } NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_ReloadPlugins: reloadPages=%d\n", reloadPages)); nsCOMPtr pluginHost(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID)); if (!pluginHost) return; pluginHost->ReloadPlugins(); } void _invalidaterect(NPP npp, NPRect* invalidRect) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_invalidaterect called from the wrong thread\n")); return; } NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_InvalidateRect: npp=%p, top=%d, left=%d, bottom=%d, " "right=%d\n", (void*)npp, invalidRect->top, invalidRect->left, invalidRect->bottom, invalidRect->right)); if (!npp || !npp->ndata) { NS_WARNING("_invalidaterect: npp or npp->ndata == 0"); return; } nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)npp->ndata; PluginDestructionGuard guard(inst); inst->InvalidateRect((NPRect*)invalidRect); } void _invalidateregion(NPP npp, NPRegion invalidRegion) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_invalidateregion called from the wrong thread\n")); return; } NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_InvalidateRegion: npp=%p, region=%p\n", (void*)npp, (void*)invalidRegion)); if (!npp || !npp->ndata) { NS_WARNING("_invalidateregion: npp or npp->ndata == 0"); return; } nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)npp->ndata; PluginDestructionGuard guard(inst); inst->InvalidateRegion((NPRegion)invalidRegion); } void _forceredraw(NPP npp) {} NPObject* _getwindowobject(NPP npp) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_getwindowobject called from the wrong thread\n")); return nullptr; } // The window want to return here is the outer window, *not* the inner (since // we don't know what the plugin will do with it). Document* doc = GetDocumentFromNPP(npp); NS_ENSURE_TRUE(doc, nullptr); nsCOMPtr outer = doc->GetWindow(); NS_ENSURE_TRUE(outer, nullptr); JS::Rooted windowProxy( dom::RootingCx(), nsGlobalWindowOuter::Cast(outer)->GetGlobalJSObject()); JS::Rooted global(dom::RootingCx(), JS::GetNonCCWObjectGlobal(windowProxy)); return nsJSObjWrapper::GetNewOrUsed(npp, windowProxy, global); } NPObject* _getpluginelement(NPP npp) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_getpluginelement called from the wrong thread\n")); return nullptr; } nsNPAPIPluginInstance* inst = static_cast(npp->ndata); if (!inst) return nullptr; RefPtr element; inst->GetDOMElement(getter_AddRefs(element)); if (!element) return nullptr; Document* doc = GetDocumentFromNPP(npp); if (NS_WARN_IF(!doc)) { return nullptr; } dom::AutoJSAPI jsapi; if (NS_WARN_IF(!jsapi.Init(doc->GetInnerWindow()))) { return nullptr; } JSContext* cx = jsapi.cx(); nsCOMPtr xpc(nsIXPConnect::XPConnect()); NS_ENSURE_TRUE(xpc, nullptr); JS::RootedValue val(cx); if (!ToJSValue(cx, element, &val)) { return nullptr; } if (NS_WARN_IF(!val.isObject())) { return nullptr; } JS::RootedObject obj(cx, &val.toObject()); JS::RootedObject global(cx, JS::CurrentGlobalOrNull(cx)); return nsJSObjWrapper::GetNewOrUsed(npp, obj, global); } NPIdentifier _getstringidentifier(const NPUTF8* name) { if (!name) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_getstringidentifier: passed null name")); return nullptr; } if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_getstringidentifier called from the wrong thread\n")); } AutoSafeJSContext cx; return doGetIdentifier(cx, name); } void _getstringidentifiers(const NPUTF8** names, int32_t nameCount, NPIdentifier* identifiers) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_getstringidentifiers called from the wrong thread\n")); } AutoSafeJSContext cx; for (int32_t i = 0; i < nameCount; ++i) { if (names[i]) { identifiers[i] = doGetIdentifier(cx, names[i]); } else { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_getstringidentifiers: passed null name")); identifiers[i] = nullptr; } } } NPIdentifier _getintidentifier(int32_t intid) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_getstringidentifier called from the wrong thread\n")); } return IntToNPIdentifier(intid); } NPUTF8* _utf8fromidentifier(NPIdentifier id) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_utf8fromidentifier called from the wrong thread\n")); } if (!id) return nullptr; if (!NPIdentifierIsString(id)) { return nullptr; } JSString* str = NPIdentifierToString(id); nsAutoString autoStr; AssignJSLinearString(autoStr, JS_ASSERT_STRING_IS_LINEAR(str)); return ToNewUTF8String(autoStr); } int32_t _intfromidentifier(NPIdentifier id) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_intfromidentifier called from the wrong thread\n")); } if (!NPIdentifierIsInt(id)) { return INT32_MIN; } return NPIdentifierToInt(id); } bool _identifierisstring(NPIdentifier id) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_identifierisstring called from the wrong thread\n")); } return NPIdentifierIsString(id); } NPObject* _createobject(NPP npp, NPClass* aClass) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_createobject called from the wrong thread\n")); return nullptr; } if (!npp) { NS_ERROR("Null npp passed to _createobject()!"); return nullptr; } PluginDestructionGuard guard(npp); if (!aClass) { NS_ERROR("Null class passed to _createobject()!"); return nullptr; } NPPAutoPusher nppPusher(npp); NPObject* npobj; if (aClass->allocate) { npobj = aClass->allocate(npp, aClass); } else { npobj = (NPObject*)malloc(sizeof(NPObject)); } if (npobj) { npobj->_class = aClass; npobj->referenceCount = 1; NS_LOG_ADDREF(npobj, 1, "BrowserNPObject", sizeof(NPObject)); } NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("Created NPObject %p, NPClass %p\n", npobj, aClass)); return npobj; } NPObject* _retainobject(NPObject* npobj) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_retainobject called from the wrong thread\n")); } if (npobj) { #ifdef NS_BUILD_REFCNT_LOGGING int32_t refCnt = #endif PR_ATOMIC_INCREMENT((int32_t*)&npobj->referenceCount); NS_LOG_ADDREF(npobj, refCnt, "BrowserNPObject", sizeof(NPObject)); } return npobj; } void _releaseobject(NPObject* npobj) { // If nothing is passed, just return, even if we're on the wrong thread. if (!npobj) { return; } int32_t refCnt = PR_ATOMIC_DECREMENT((int32_t*)&npobj->referenceCount); NS_LOG_RELEASE(npobj, refCnt, "BrowserNPObject"); if (refCnt == 0) { nsNPObjWrapper::OnDestroy(npobj); NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("Deleting NPObject %p, refcount hit 0\n", npobj)); if (npobj->_class && npobj->_class->deallocate) { npobj->_class->deallocate(npobj); } else { free(npobj); } } } bool _invoke(NPP npp, NPObject* npobj, NPIdentifier method, const NPVariant* args, uint32_t argCount, NPVariant* result) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_invoke called from the wrong thread\n")); return false; } if (!npp || !npobj || !npobj->_class || !npobj->_class->invoke) return false; PluginDestructionGuard guard(npp); NPPExceptionAutoHolder nppExceptionHolder; NPPAutoPusher nppPusher(npp); NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_Invoke(npp %p, npobj %p, method %p, args %d\n", npp, npobj, method, argCount)); return npobj->_class->invoke(npobj, method, args, argCount, result); } bool _invokeDefault(NPP npp, NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_invokedefault called from the wrong thread\n")); return false; } if (!npp || !npobj || !npobj->_class || !npobj->_class->invokeDefault) return false; NPPExceptionAutoHolder nppExceptionHolder; NPPAutoPusher nppPusher(npp); NPN_PLUGIN_LOG( PLUGIN_LOG_NOISY, ("NPN_InvokeDefault(npp %p, npobj %p, args %d\n", npp, npobj, argCount)); return npobj->_class->invokeDefault(npobj, args, argCount, result); } bool _evaluate(NPP npp, NPObject* npobj, NPString* script, NPVariant* result) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_evaluate called from the wrong thread\n")); return false; } if (!npp) return false; NPPAutoPusher nppPusher(npp); Document* doc = GetDocumentFromNPP(npp); NS_ENSURE_TRUE(doc, false); nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(doc->GetInnerWindow()); if (NS_WARN_IF(!win || !win->HasJSGlobal())) { return false; } nsAutoMicroTask mt; dom::AutoEntryScript aes(win, "NPAPI NPN_evaluate"); JSContext* cx = aes.cx(); JS::Rooted obj(cx, nsNPObjWrapper::GetNewOrUsed(npp, cx, npobj)); if (!obj) { return false; } obj = js::ToWindowIfWindowProxy(obj); MOZ_ASSERT(obj, "ToWindowIfWindowProxy should never return null"); if (result) { // Initialize the out param to void VOID_TO_NPVARIANT(*result); } if (!script || !script->UTF8Length || !script->UTF8Characters) { // Nothing to evaluate. return true; } NS_ConvertUTF8toUTF16 utf16script(script->UTF8Characters, script->UTF8Length); nsIPrincipal* principal = doc->NodePrincipal(); nsCString specStr; const char* spec; principal->GetAsciiSpec(specStr); spec = specStr.get(); if (specStr.IsEmpty()) { // No URI in a principal means it's the system principal. If the // document URI is a chrome:// URI, pass that in as the URI of the // script, else pass in null for the filename as there's no way to // know where this document really came from. Passing in null here // also means that the script gets treated by XPConnect as if it // needs additional protection, which is what we want for unknown // chrome code anyways. nsCOMPtr uri = doc->GetDocumentURI(); if (uri && uri->SchemeIs("chrome")) { uri->GetSpec(specStr); spec = specStr.get(); } else { spec = nullptr; } } NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_Evaluate(npp %p, npobj %p, script <<<%s>>>) called\n", npp, npobj, script->UTF8Characters)); JS::CompileOptions options(cx); options.setFileAndLine(spec, 0); JS::Rooted rval(cx); JS::RootedVector scopeChain(cx); if (!JS_IsGlobalObject(obj) && !scopeChain.append(obj)) { return false; } // nsNPObjWrapper::GetNewOrUsed returns an object in the current compartment // of the JSContext (it might be a CCW). MOZ_RELEASE_ASSERT(JS::GetCompartment(obj) == js::GetContextCompartment(cx), "nsNPObjWrapper::GetNewOrUsed must wrap its return value"); obj = JS::CurrentGlobalOrNull(cx); MOZ_ASSERT(obj); nsresult rv = NS_OK; { JSExecutionContext exec(cx, obj); exec.SetScopeChain(scopeChain); exec.Compile(options, utf16script); rv = exec.ExecScript(&rval); } if (!JS_WrapValue(cx, &rval)) { return false; } return NS_SUCCEEDED(rv) && (!result || JSValToNPVariant(npp, cx, rval, result)); } bool _getproperty(NPP npp, NPObject* npobj, NPIdentifier property, NPVariant* result) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_getproperty called from the wrong thread\n")); return false; } if (!npp || !npobj || !npobj->_class || !npobj->_class->getProperty) return false; NPPExceptionAutoHolder nppExceptionHolder; NPPAutoPusher nppPusher(npp); NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_GetProperty(npp %p, npobj %p, property %p) called\n", npp, npobj, property)); if (!npobj->_class->getProperty(npobj, property, result)) return false; return true; } bool _setproperty(NPP npp, NPObject* npobj, NPIdentifier property, const NPVariant* value) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_setproperty called from the wrong thread\n")); return false; } if (!npp || !npobj || !npobj->_class || !npobj->_class->setProperty) return false; NPPExceptionAutoHolder nppExceptionHolder; NPPAutoPusher nppPusher(npp); NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_SetProperty(npp %p, npobj %p, property %p) called\n", npp, npobj, property)); return npobj->_class->setProperty(npobj, property, value); } bool _removeproperty(NPP npp, NPObject* npobj, NPIdentifier property) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_removeproperty called from the wrong thread\n")); return false; } if (!npp || !npobj || !npobj->_class || !npobj->_class->removeProperty) return false; NPPExceptionAutoHolder nppExceptionHolder; NPPAutoPusher nppPusher(npp); NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_RemoveProperty(npp %p, npobj %p, property %p) called\n", npp, npobj, property)); return npobj->_class->removeProperty(npobj, property); } bool _hasproperty(NPP npp, NPObject* npobj, NPIdentifier propertyName) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_hasproperty called from the wrong thread\n")); return false; } if (!npp || !npobj || !npobj->_class || !npobj->_class->hasProperty) return false; NPPExceptionAutoHolder nppExceptionHolder; NPPAutoPusher nppPusher(npp); NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_HasProperty(npp %p, npobj %p, property %p) called\n", npp, npobj, propertyName)); return npobj->_class->hasProperty(npobj, propertyName); } bool _hasmethod(NPP npp, NPObject* npobj, NPIdentifier methodName) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_hasmethod called from the wrong thread\n")); return false; } if (!npp || !npobj || !npobj->_class || !npobj->_class->hasMethod) return false; NPPExceptionAutoHolder nppExceptionHolder; NPPAutoPusher nppPusher(npp); NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_HasMethod(npp %p, npobj %p, property %p) called\n", npp, npobj, methodName)); return npobj->_class->hasMethod(npobj, methodName); } bool _enumerate(NPP npp, NPObject* npobj, NPIdentifier** identifier, uint32_t* count) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_enumerate called from the wrong thread\n")); return false; } if (!npp || !npobj || !npobj->_class) return false; NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_Enumerate(npp %p, npobj %p) called\n", npp, npobj)); if (!NP_CLASS_STRUCT_VERSION_HAS_ENUM(npobj->_class) || !npobj->_class->enumerate) { *identifier = 0; *count = 0; return true; } NPPExceptionAutoHolder nppExceptionHolder; NPPAutoPusher nppPusher(npp); return npobj->_class->enumerate(npobj, identifier, count); } bool _construct(NPP npp, NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_construct called from the wrong thread\n")); return false; } if (!npp || !npobj || !npobj->_class || !NP_CLASS_STRUCT_VERSION_HAS_CTOR(npobj->_class) || !npobj->_class->construct) { return false; } NPPExceptionAutoHolder nppExceptionHolder; NPPAutoPusher nppPusher(npp); return npobj->_class->construct(npobj, args, argCount, result); } void _releasevariantvalue(NPVariant* variant) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_releasevariantvalue called from the wrong thread\n")); } switch (variant->type) { case NPVariantType_Void: case NPVariantType_Null: case NPVariantType_Bool: case NPVariantType_Int32: case NPVariantType_Double: break; case NPVariantType_String: { const NPString* s = &NPVARIANT_TO_STRING(*variant); if (s->UTF8Characters) { #if defined(MOZ_MEMORY) && defined(XP_WIN) if (malloc_usable_size((void*)s->UTF8Characters) != 0) { free((void*)s->UTF8Characters); } else { void* p = (void*)s->UTF8Characters; DWORD nheaps = 0; AutoTArray heaps; nheaps = GetProcessHeaps(0, heaps.Elements()); heaps.AppendElements(nheaps); GetProcessHeaps(nheaps, heaps.Elements()); for (DWORD i = 0; i < nheaps; i++) { if (InHeap(heaps[i], p)) { HeapFree(heaps[i], 0, p); break; } } } #else free((void*)s->UTF8Characters); #endif } break; } case NPVariantType_Object: { NPObject* npobj = NPVARIANT_TO_OBJECT(*variant); if (npobj) _releaseobject(npobj); break; } default: NS_ERROR("Unknown NPVariant type!"); } VOID_TO_NPVARIANT(*variant); } void _setexception(NPObject* npobj, const NPUTF8* message) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_setexception called from the wrong thread\n")); return; } if (!message) return; if (gNPPException) { // If a plugin throws multiple exceptions, we'll only report the // last one for now. free(gNPPException); } gNPPException = strdup(message); } NPError _getvalue(NPP npp, NPNVariable variable, void* result) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_getvalue called from the wrong thread\n")); return NPERR_INVALID_PARAM; } NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetValue: npp=%p, var=%d\n", (void*)npp, (int)variable)); nsresult res; PluginDestructionGuard guard(npp); // Cast NPNVariable enum to int to avoid warnings about including switch // cases for android_npapi.h's non-standard ANPInterface values. switch (static_cast(variable)) { #if defined(XP_UNIX) && !defined(XP_MACOSX) case NPNVxDisplay: { # if defined(MOZ_X11) if (npp) { nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)npp->ndata; bool windowless = false; inst->IsWindowless(&windowless); // The documentation on the types for many variables in NP(N|P)_GetValue // is vague. Often boolean values are NPBool (1 byte), but // https://developer.mozilla.org/en/XEmbed_Extension_for_Mozilla_Plugins // treats NPPVpluginNeedsXEmbed as PRBool (int), and // on x86/32-bit, flash stores to this using |movl 0x1,&needsXEmbed|. // thus we can't use NPBool for needsXEmbed, or the three bytes above // it on the stack would get clobbered. so protect with the larger bool. int needsXEmbed = 0; if (!windowless) { res = inst->GetValueFromPlugin(NPPVpluginNeedsXEmbed, &needsXEmbed); // If the call returned an error code make sure we still use our // default value. if (NS_FAILED(res)) { needsXEmbed = 0; } } if (windowless || needsXEmbed) { (*(Display**)result) = mozilla::DefaultXDisplay(); return NPERR_NO_ERROR; } } # endif return NPERR_GENERIC_ERROR; } case NPNVxtAppContext: return NPERR_GENERIC_ERROR; #endif #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) case NPNVnetscapeWindow: { if (!npp || !npp->ndata) return NPERR_INVALID_INSTANCE_ERROR; nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)npp->ndata; RefPtr owner = inst->GetOwner(); NS_ENSURE_TRUE(owner, NPERR_NO_ERROR); if (NS_SUCCEEDED(owner->GetNetscapeWindow(result))) { return NPERR_NO_ERROR; } return NPERR_GENERIC_ERROR; } #endif case NPNVjavascriptEnabledBool: { *(NPBool*)result = false; bool js = false; res = Preferences::GetBool("javascript.enabled", &js); if (NS_SUCCEEDED(res)) { *(NPBool*)result = js; } return NPERR_NO_ERROR; } case NPNVasdEnabledBool: *(NPBool*)result = false; return NPERR_NO_ERROR; case NPNVisOfflineBool: { bool offline = false; nsCOMPtr ioservice = do_GetService(NS_IOSERVICE_CONTRACTID, &res); if (NS_SUCCEEDED(res)) res = ioservice->GetOffline(&offline); if (NS_FAILED(res)) return NPERR_GENERIC_ERROR; *(NPBool*)result = offline; return NPERR_NO_ERROR; } case NPNVToolkit: { #ifdef MOZ_WIDGET_GTK *((NPNToolkitType*)result) = NPNVGtk2; #endif if (*(NPNToolkitType*)result) return NPERR_NO_ERROR; return NPERR_GENERIC_ERROR; } case NPNVSupportsXEmbedBool: { #ifdef MOZ_WIDGET_GTK *(NPBool*)result = true; #else *(NPBool*)result = false; #endif return NPERR_NO_ERROR; } case NPNVWindowNPObject: { *(NPObject**)result = _getwindowobject(npp); return *(NPObject**)result ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR; } case NPNVPluginElementNPObject: { *(NPObject**)result = _getpluginelement(npp); return *(NPObject**)result ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR; } case NPNVSupportsWindowless: { #if defined(XP_WIN) || defined(XP_MACOSX) || \ (defined(MOZ_X11) && defined(MOZ_WIDGET_GTK)) *(NPBool*)result = true; #else *(NPBool*)result = false; #endif return NPERR_NO_ERROR; } case NPNVprivateModeBool: { bool privacy; nsNPAPIPluginInstance* inst = static_cast(npp->ndata); if (!inst) return NPERR_GENERIC_ERROR; nsresult rv = inst->IsPrivateBrowsing(&privacy); if (NS_FAILED(rv)) return NPERR_GENERIC_ERROR; *(NPBool*)result = (NPBool)privacy; return NPERR_NO_ERROR; } case NPNVdocumentOrigin: { nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)npp->ndata; if (!inst) { return NPERR_GENERIC_ERROR; } RefPtr element; inst->GetDOMElement(getter_AddRefs(element)); if (!element) { return NPERR_GENERIC_ERROR; } nsIPrincipal* principal = element->NodePrincipal(); nsAutoString utf16Origin; res = nsContentUtils::GetUTFOrigin(principal, utf16Origin); if (NS_FAILED(res)) { return NPERR_GENERIC_ERROR; } nsCOMPtr idnService = do_GetService(NS_IDNSERVICE_CONTRACTID); if (!idnService) { return NPERR_GENERIC_ERROR; } // This is a bit messy: we convert to UTF-8 here, but then // nsIDNService::Normalize will convert back to UTF-16 for processing, // and back to UTF-8 again to return the result. // Alternative: perhaps we should add a NormalizeUTF16 version of the API, // and just convert to UTF-8 for the final return (resulting in one // encoding form conversion instead of three). NS_ConvertUTF16toUTF8 utf8Origin(utf16Origin); nsAutoCString normalizedUTF8Origin; res = idnService->Normalize(utf8Origin, normalizedUTF8Origin); if (NS_FAILED(res)) { return NPERR_GENERIC_ERROR; } *(char**)result = ToNewCString(normalizedUTF8Origin); return *(char**)result ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR; } #ifdef XP_MACOSX case NPNVpluginDrawingModel: { if (npp) { nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)npp->ndata; if (inst) { NPDrawingModel drawingModel; inst->GetDrawingModel((int32_t*)&drawingModel); *(NPDrawingModel*)result = drawingModel; return NPERR_NO_ERROR; } } return NPERR_GENERIC_ERROR; } # ifndef NP_NO_QUICKDRAW case NPNVsupportsQuickDrawBool: { *(NPBool*)result = false; return NPERR_NO_ERROR; } # endif case NPNVsupportsCoreGraphicsBool: { *(NPBool*)result = true; return NPERR_NO_ERROR; } case NPNVsupportsCoreAnimationBool: { *(NPBool*)result = true; return NPERR_NO_ERROR; } case NPNVsupportsInvalidatingCoreAnimationBool: { *(NPBool*)result = true; return NPERR_NO_ERROR; } case NPNVsupportsCompositingCoreAnimationPluginsBool: { *(NPBool*)result = PR_TRUE; return NPERR_NO_ERROR; } # ifndef NP_NO_CARBON case NPNVsupportsCarbonBool: { *(NPBool*)result = false; return NPERR_NO_ERROR; } # endif case NPNVsupportsCocoaBool: { *(NPBool*)result = true; return NPERR_NO_ERROR; } case NPNVsupportsUpdatedCocoaTextInputBool: { *(NPBool*)result = true; return NPERR_NO_ERROR; } #endif #if defined(XP_MACOSX) || defined(XP_WIN) case NPNVcontentsScaleFactor: { nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)(npp ? npp->ndata : nullptr); double scaleFactor = inst ? inst->GetContentsScaleFactor() : 1.0; *(double*)result = scaleFactor; return NPERR_NO_ERROR; } #endif case NPNVCSSZoomFactor: { nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)(npp ? npp->ndata : nullptr); double scaleFactor = inst ? inst->GetCSSZoomFactor() : 1.0; *(double*)result = scaleFactor; return NPERR_NO_ERROR; } // we no longer hand out any XPCOM objects case NPNVDOMElement: case NPNVDOMWindow: case NPNVserviceManager: // old XPCOM objects, no longer supported, but null out the out // param to avoid crashing plugins that still try to use this. *(nsISupports**)result = nullptr; [[fallthrough]]; default: NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_getvalue unhandled get value: %d\n", variable)); return NPERR_GENERIC_ERROR; } } NPError _setvalue(NPP npp, NPPVariable variable, void* result) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_setvalue called from the wrong thread\n")); return NPERR_INVALID_PARAM; } NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_SetValue: npp=%p, var=%d\n", (void*)npp, (int)variable)); if (!npp) return NPERR_INVALID_INSTANCE_ERROR; nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)npp->ndata; NS_ASSERTION(inst, "null instance"); if (!inst) return NPERR_INVALID_INSTANCE_ERROR; PluginDestructionGuard guard(inst); // Cast NPNVariable enum to int to avoid warnings about including switch // cases for android_npapi.h's non-standard ANPInterface values. switch (static_cast(variable)) { // we should keep backward compatibility with NPAPI where the // actual pointer value is checked rather than its content // when passing booleans case NPPVpluginWindowBool: { #ifdef XP_MACOSX // This setting doesn't apply to OS X (only to Windows and Unix/Linux). // See https://developer.mozilla.org/En/NPN_SetValue#section_5. Return // NPERR_NO_ERROR here to conform to other browsers' behavior on OS X // (e.g. Safari and Opera). return NPERR_NO_ERROR; #else NPBool bWindowless = (result == nullptr); return inst->SetWindowless(bWindowless); #endif } case NPPVpluginTransparentBool: { NPBool bTransparent = (result != nullptr); return inst->SetTransparent(bTransparent); } case NPPVjavascriptPushCallerBool: { return NPERR_NO_ERROR; } case NPPVpluginKeepLibraryInMemory: { NPBool bCached = (result != nullptr); inst->SetCached(bCached); return NPERR_NO_ERROR; } case NPPVpluginUsesDOMForCursorBool: { bool useDOMForCursor = (result != nullptr); return inst->SetUsesDOMForCursor(useDOMForCursor); } case NPPVpluginIsPlayingAudio: { const bool isPlaying = result; nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)npp->ndata; MOZ_ASSERT(inst); if (!isPlaying && !inst->HasAudioChannelAgent()) { return NPERR_NO_ERROR; } if (isPlaying) { inst->NotifyStartedPlaying(); } else { inst->NotifyStoppedPlaying(); } return NPERR_NO_ERROR; } case NPPVpluginDrawingModel: { if (inst) { inst->SetDrawingModel((NPDrawingModel)NS_PTR_TO_INT32(result)); return NPERR_NO_ERROR; } return NPERR_GENERIC_ERROR; } #ifdef XP_MACOSX case NPPVpluginEventModel: { if (inst) { inst->SetEventModel((NPEventModel)NS_PTR_TO_INT32(result)); return NPERR_NO_ERROR; } else { return NPERR_GENERIC_ERROR; } } #endif default: return NPERR_GENERIC_ERROR; } } NPError _requestread(NPStream* pstream, NPByteRange* rangeList) { return NPERR_STREAM_NOT_SEEKABLE; } // Deprecated, only stubbed out void* /* OJI type: JRIEnv* */ _getJavaEnv() { NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetJavaEnv\n")); return nullptr; } const char* _useragent(NPP npp) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_useragent called from the wrong thread\n")); return nullptr; } NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_UserAgent: npp=%p\n", (void*)npp)); nsCOMPtr pluginHostCOM( do_GetService(MOZ_PLUGIN_HOST_CONTRACTID)); nsPluginHost* pluginHost = static_cast(pluginHostCOM.get()); if (!pluginHost) { return nullptr; } const char* retstr; nsresult rv = pluginHost->UserAgent(&retstr); if (NS_FAILED(rv)) return nullptr; return retstr; } void* _memalloc(uint32_t size) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_memalloc called from the wrong thread\n")); } NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_MemAlloc: size=%d\n", size)); return moz_xmalloc(size); } // Deprecated, only stubbed out void* /* OJI type: jref */ _getJavaPeer(NPP npp) { NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetJavaPeer: npp=%p\n", (void*)npp)); return nullptr; } void _pushpopupsenabledstate(NPP npp, NPBool enabled) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG( PLUGIN_LOG_ALWAYS, ("NPN_pushpopupsenabledstate called from the wrong thread\n")); return; } nsNPAPIPluginInstance* inst = npp ? (nsNPAPIPluginInstance*)npp->ndata : nullptr; if (!inst) return; inst->PushPopupsEnabledState(enabled); } void _poppopupsenabledstate(NPP npp) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG( PLUGIN_LOG_ALWAYS, ("NPN_poppopupsenabledstate called from the wrong thread\n")); return; } nsNPAPIPluginInstance* inst = npp ? (nsNPAPIPluginInstance*)npp->ndata : nullptr; if (!inst) return; inst->PopPopupsEnabledState(); } NPError _getvalueforurl(NPP instance, NPNURLVariable variable, const char* url, char** value, uint32_t* len) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_getvalueforurl called from the wrong thread\n")); return NPERR_GENERIC_ERROR; } if (!instance) { return NPERR_INVALID_PARAM; } if (!url || !*url || !len) { return NPERR_INVALID_URL; } *len = 0; switch (variable) { case NPNURLVProxy: // NPNURLVProxy is no longer supported. *value = nullptr; return NPERR_GENERIC_ERROR; case NPNURLVCookie: // NPNURLVCookie is no longer supported. *value = nullptr; return NPERR_GENERIC_ERROR; default: // Fall through and return an error... ; } return NPERR_GENERIC_ERROR; } NPError _setvalueforurl(NPP instance, NPNURLVariable variable, const char* url, const char* value, uint32_t len) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_setvalueforurl called from the wrong thread\n")); return NPERR_GENERIC_ERROR; } if (!instance) { return NPERR_INVALID_PARAM; } if (!url || !*url) { return NPERR_INVALID_URL; } switch (variable) { case NPNURLVCookie: // NPNURLVCookie is no longer supported. return NPERR_GENERIC_ERROR; case NPNURLVProxy: // We don't support setting proxy values, fall through... default: // Fall through and return an error... ; } return NPERR_GENERIC_ERROR; } uint32_t _scheduletimer(NPP instance, uint32_t interval, NPBool repeat, PluginTimerFunc timerFunc) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_scheduletimer called from the wrong thread\n")); return 0; } nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)instance->ndata; if (!inst) return 0; return inst->ScheduleTimer(interval, repeat, timerFunc); } void _unscheduletimer(NPP instance, uint32_t timerID) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_unscheduletimer called from the wrong thread\n")); return; } nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)instance->ndata; if (!inst) return; inst->UnscheduleTimer(timerID); } NPError _popupcontextmenu(NPP instance, NPMenu* menu) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_popupcontextmenu called from the wrong thread\n")); return 0; } #ifdef MOZ_WIDGET_COCOA nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)instance->ndata; double pluginX, pluginY; double screenX, screenY; const NPCocoaEvent* currentEvent = static_cast(inst->GetCurrentEvent()); if (!currentEvent) { return NPERR_GENERIC_ERROR; } // Ensure that the events has an x/y value. if (currentEvent->type != NPCocoaEventMouseDown && currentEvent->type != NPCocoaEventMouseUp && currentEvent->type != NPCocoaEventMouseMoved && currentEvent->type != NPCocoaEventMouseEntered && currentEvent->type != NPCocoaEventMouseExited && currentEvent->type != NPCocoaEventMouseDragged) { return NPERR_GENERIC_ERROR; } pluginX = currentEvent->data.mouse.pluginX; pluginY = currentEvent->data.mouse.pluginY; if ((pluginX < 0.0) || (pluginY < 0.0)) return NPERR_GENERIC_ERROR; NPBool success = _convertpoint(instance, pluginX, pluginY, NPCoordinateSpacePlugin, &screenX, &screenY, NPCoordinateSpaceScreen); if (success) { return mozilla::plugins::PluginUtilsOSX::ShowCocoaContextMenu( menu, screenX, screenY, nullptr, nullptr); } else { NS_WARNING("Convertpoint failed, could not created contextmenu."); return NPERR_GENERIC_ERROR; } #else NS_WARNING("Not supported on this platform!"); return NPERR_GENERIC_ERROR; #endif } NPBool _convertpoint(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double* destX, double* destY, NPCoordinateSpace destSpace) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_convertpoint called from the wrong thread\n")); return 0; } nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)instance->ndata; if (!inst) return false; return inst->ConvertPoint(sourceX, sourceY, sourceSpace, destX, destY, destSpace); } void _urlredirectresponse(NPP instance, void* notifyData, NPBool allow) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_convertpoint called from the wrong thread\n")); return; } nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)instance->ndata; if (!inst) { return; } inst->URLRedirectResponse(notifyData, allow); } NPError _initasyncsurface(NPP instance, NPSize* size, NPImageFormat format, void* initData, NPAsyncSurface* surface) { nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)instance->ndata; if (!inst) { return NPERR_GENERIC_ERROR; } return inst->InitAsyncSurface(size, format, initData, surface); } NPError _finalizeasyncsurface(NPP instance, NPAsyncSurface* surface) { nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)instance->ndata; if (!inst) { return NPERR_GENERIC_ERROR; } return inst->FinalizeAsyncSurface(surface); } void _setcurrentasyncsurface(NPP instance, NPAsyncSurface* surface, NPRect* changed) { nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)instance->ndata; if (!inst) { return; } inst->SetCurrentAsyncSurface(surface, changed); } } // namespace mozilla::plugins::parent