summaryrefslogtreecommitdiffstats
path: root/dom/plugins/base/nsNPAPIPluginInstance.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/plugins/base/nsNPAPIPluginInstance.cpp')
-rw-r--r--dom/plugins/base/nsNPAPIPluginInstance.cpp1861
1 files changed, 1861 insertions, 0 deletions
diff --git a/dom/plugins/base/nsNPAPIPluginInstance.cpp b/dom/plugins/base/nsNPAPIPluginInstance.cpp
new file mode 100644
index 000000000..4b211ed7e
--- /dev/null
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -0,0 +1,1861 @@
+/* -*- 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 "mozilla/DebugOnly.h"
+
+#ifdef MOZ_WIDGET_ANDROID
+// For ScreenOrientation.h and Hal.h
+#include "base/basictypes.h"
+#endif
+
+#include "mozilla/Logging.h"
+#include "prmem.h"
+#include "nscore.h"
+#include "prenv.h"
+
+#include "nsNPAPIPluginInstance.h"
+#include "nsNPAPIPlugin.h"
+#include "nsNPAPIPluginStreamListener.h"
+#include "nsPluginHost.h"
+#include "nsPluginLogging.h"
+#include "nsContentUtils.h"
+#include "nsPluginInstanceOwner.h"
+
+#include "nsThreadUtils.h"
+#include "nsIDOMElement.h"
+#include "nsIDocument.h"
+#include "nsIDocShell.h"
+#include "nsIScriptGlobalObject.h"
+#include "nsIScriptContext.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsJSNPRuntime.h"
+#include "nsPluginStreamListenerPeer.h"
+#include "nsSize.h"
+#include "nsNetCID.h"
+#include "nsIContent.h"
+#include "nsVersionComparator.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/Unused.h"
+#include "nsILoadContext.h"
+#include "mozilla/dom/HTMLObjectElementBinding.h"
+#include "AudioChannelService.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+#ifdef MOZ_WIDGET_ANDROID
+#include "ANPBase.h"
+#include <android/log.h>
+#include "android_npapi.h"
+#include "mozilla/Mutex.h"
+#include "mozilla/CondVar.h"
+#include "mozilla/dom/ScreenOrientation.h"
+#include "mozilla/Hal.h"
+#include "GLContextProvider.h"
+#include "GLContext.h"
+#include "TexturePoolOGL.h"
+#include "SurfaceTypes.h"
+#include "EGLUtils.h"
+
+using namespace mozilla;
+using namespace mozilla::gl;
+
+typedef nsNPAPIPluginInstance::VideoInfo VideoInfo;
+
+class PluginEventRunnable : public Runnable
+{
+public:
+ PluginEventRunnable(nsNPAPIPluginInstance* instance, ANPEvent* event)
+ : mInstance(instance), mEvent(*event), mCanceled(false) {}
+
+ virtual nsresult Run() {
+ if (mCanceled)
+ return NS_OK;
+
+ mInstance->HandleEvent(&mEvent, nullptr);
+ mInstance->PopPostedEvent(this);
+ return NS_OK;
+ }
+
+ void Cancel() { mCanceled = true; }
+private:
+ nsNPAPIPluginInstance* mInstance;
+ ANPEvent mEvent;
+ bool mCanceled;
+};
+
+static RefPtr<GLContext> sPluginContext = nullptr;
+
+static bool EnsureGLContext()
+{
+ if (!sPluginContext) {
+ const auto flags = CreateContextFlags::REQUIRE_COMPAT_PROFILE;
+ nsCString discardedFailureId;
+ sPluginContext = GLContextProvider::CreateHeadless(flags, &discardedFailureId);
+ }
+
+ return sPluginContext != nullptr;
+}
+
+static std::map<NPP, nsNPAPIPluginInstance*> sPluginNPPMap;
+
+#endif
+
+using namespace mozilla;
+using namespace mozilla::plugins::parent;
+using namespace mozilla::layers;
+
+static NS_DEFINE_IID(kIOutputStreamIID, NS_IOUTPUTSTREAM_IID);
+
+NS_IMPL_ISUPPORTS(nsNPAPIPluginInstance, nsIAudioChannelAgentCallback)
+
+nsNPAPIPluginInstance::nsNPAPIPluginInstance()
+ : mDrawingModel(kDefaultDrawingModel)
+#ifdef MOZ_WIDGET_ANDROID
+ , mANPDrawingModel(0)
+ , mFullScreenOrientation(dom::eScreenOrientation_LandscapePrimary)
+ , mWakeLocked(false)
+ , mFullScreen(false)
+ , mOriginPos(gl::OriginPos::TopLeft)
+#endif
+ , mRunning(NOT_STARTED)
+ , mWindowless(false)
+ , mTransparent(false)
+ , mCached(false)
+ , mUsesDOMForCursor(false)
+ , mInPluginInitCall(false)
+ , mPlugin(nullptr)
+ , mMIMEType(nullptr)
+ , mOwner(nullptr)
+#ifdef XP_MACOSX
+ , mCurrentPluginEvent(nullptr)
+#endif
+#ifdef MOZ_WIDGET_ANDROID
+ , mOnScreen(true)
+#endif
+ , mHaveJavaC2PJSObjectQuirk(false)
+ , mCachedParamLength(0)
+ , mCachedParamNames(nullptr)
+ , mCachedParamValues(nullptr)
+ , mMuted(false)
+{
+ mNPP.pdata = nullptr;
+ mNPP.ndata = this;
+
+ PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance ctor: this=%p\n",this));
+
+#ifdef MOZ_WIDGET_ANDROID
+ sPluginNPPMap[&mNPP] = this;
+#endif
+}
+
+nsNPAPIPluginInstance::~nsNPAPIPluginInstance()
+{
+ PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance dtor: this=%p\n",this));
+
+#ifdef MOZ_WIDGET_ANDROID
+ sPluginNPPMap.erase(&mNPP);
+#endif
+
+ if (mMIMEType) {
+ PR_Free((void *)mMIMEType);
+ mMIMEType = nullptr;
+ }
+
+ if (!mCachedParamValues || !mCachedParamNames) {
+ return;
+ }
+ MOZ_ASSERT(mCachedParamValues && mCachedParamNames);
+
+ for (uint32_t i = 0; i < mCachedParamLength; i++) {
+ if (mCachedParamNames[i]) {
+ free(mCachedParamNames[i]);
+ mCachedParamNames[i] = nullptr;
+ }
+ if (mCachedParamValues[i]) {
+ free(mCachedParamValues[i]);
+ mCachedParamValues[i] = nullptr;
+ }
+ }
+
+ free(mCachedParamNames);
+ mCachedParamNames = nullptr;
+
+ free(mCachedParamValues);
+ mCachedParamValues = nullptr;
+}
+
+uint32_t nsNPAPIPluginInstance::gInUnsafePluginCalls = 0;
+
+void
+nsNPAPIPluginInstance::Destroy()
+{
+ Stop();
+ mPlugin = nullptr;
+ mAudioChannelAgent = nullptr;
+
+#if MOZ_WIDGET_ANDROID
+ if (mContentSurface)
+ mContentSurface->SetFrameAvailableCallback(nullptr);
+
+ mContentSurface = nullptr;
+
+ std::map<void*, VideoInfo*>::iterator it;
+ for (it = mVideos.begin(); it != mVideos.end(); it++) {
+ it->second->mSurfaceTexture->SetFrameAvailableCallback(nullptr);
+ delete it->second;
+ }
+ mVideos.clear();
+ SetWakeLock(false);
+#endif
+}
+
+TimeStamp
+nsNPAPIPluginInstance::StopTime()
+{
+ return mStopTime;
+}
+
+nsresult nsNPAPIPluginInstance::Initialize(nsNPAPIPlugin *aPlugin, nsPluginInstanceOwner* aOwner, const nsACString& aMIMEType)
+{
+ PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
+ PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::Initialize this=%p\n",this));
+
+ NS_ENSURE_ARG_POINTER(aPlugin);
+ NS_ENSURE_ARG_POINTER(aOwner);
+
+ mPlugin = aPlugin;
+ mOwner = aOwner;
+
+ if (!aMIMEType.IsEmpty()) {
+ mMIMEType = ToNewCString(aMIMEType);
+ }
+
+ return Start();
+}
+
+nsresult nsNPAPIPluginInstance::Stop()
+{
+ PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::Stop this=%p\n",this));
+
+ // Make sure the plugin didn't leave popups enabled.
+ if (mPopupStates.Length() > 0) {
+ nsCOMPtr<nsPIDOMWindowOuter> window = GetDOMWindow();
+
+ if (window) {
+ window->PopPopupControlState(openAbused);
+ }
+ }
+
+ if (RUNNING != mRunning) {
+ return NS_OK;
+ }
+
+ // clean up all outstanding timers
+ for (uint32_t i = mTimers.Length(); i > 0; i--)
+ UnscheduleTimer(mTimers[i - 1]->id);
+
+ // If there's code from this plugin instance on the stack, delay the
+ // destroy.
+ if (PluginDestructionGuard::DelayDestroy(this)) {
+ return NS_OK;
+ }
+
+ // Make sure we lock while we're writing to mRunning after we've
+ // started as other threads might be checking that inside a lock.
+ {
+ AsyncCallbackAutoLock lock;
+ mRunning = DESTROYING;
+ mStopTime = TimeStamp::Now();
+ }
+
+ OnPluginDestroy(&mNPP);
+
+ // clean up open streams
+ while (mStreamListeners.Length() > 0) {
+ RefPtr<nsNPAPIPluginStreamListener> currentListener(mStreamListeners[0]);
+ currentListener->CleanUpStream(NPRES_USER_BREAK);
+ mStreamListeners.RemoveElement(currentListener);
+ }
+
+ if (!mPlugin || !mPlugin->GetLibrary())
+ return NS_ERROR_FAILURE;
+
+ NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
+
+ NPError error = NPERR_GENERIC_ERROR;
+ if (pluginFunctions->destroy) {
+ NPSavedData *sdata = 0;
+
+ NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->destroy)(&mNPP, &sdata), this,
+ NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
+
+ NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
+ ("NPP Destroy called: this=%p, npp=%p, return=%d\n", this, &mNPP, error));
+ }
+ mRunning = DESTROYED;
+
+#if MOZ_WIDGET_ANDROID
+ for (uint32_t i = 0; i < mPostedEvents.Length(); i++) {
+ mPostedEvents[i]->Cancel();
+ }
+
+ mPostedEvents.Clear();
+#endif
+
+ nsJSNPRuntime::OnPluginDestroy(&mNPP);
+
+ if (error != NPERR_NO_ERROR)
+ return NS_ERROR_FAILURE;
+ else
+ return NS_OK;
+}
+
+already_AddRefed<nsPIDOMWindowOuter>
+nsNPAPIPluginInstance::GetDOMWindow()
+{
+ if (!mOwner)
+ return nullptr;
+
+ RefPtr<nsPluginInstanceOwner> kungFuDeathGrip(mOwner);
+
+ nsCOMPtr<nsIDocument> doc;
+ kungFuDeathGrip->GetDocument(getter_AddRefs(doc));
+ if (!doc)
+ return nullptr;
+
+ RefPtr<nsPIDOMWindowOuter> window = doc->GetWindow();
+
+ return window.forget();
+}
+
+nsresult
+nsNPAPIPluginInstance::GetTagType(nsPluginTagType *result)
+{
+ if (!mOwner) {
+ return NS_ERROR_FAILURE;
+ }
+
+ return mOwner->GetTagType(result);
+}
+
+nsresult
+nsNPAPIPluginInstance::GetMode(int32_t *result)
+{
+ if (mOwner)
+ return mOwner->GetMode(result);
+ else
+ return NS_ERROR_FAILURE;
+}
+
+nsTArray<nsNPAPIPluginStreamListener*>*
+nsNPAPIPluginInstance::StreamListeners()
+{
+ return &mStreamListeners;
+}
+
+nsTArray<nsPluginStreamListenerPeer*>*
+nsNPAPIPluginInstance::FileCachedStreamListeners()
+{
+ return &mFileCachedStreamListeners;
+}
+
+nsresult
+nsNPAPIPluginInstance::Start()
+{
+ if (mRunning == RUNNING) {
+ return NS_OK;
+ }
+
+ if (!mOwner) {
+ MOZ_ASSERT(false, "Should not be calling Start() on unowned plugin.");
+ return NS_ERROR_FAILURE;
+ }
+
+ PluginDestructionGuard guard(this);
+
+ nsTArray<MozPluginParameter> attributes;
+ nsTArray<MozPluginParameter> params;
+
+ nsPluginTagType tagtype;
+ nsresult rv = GetTagType(&tagtype);
+ if (NS_SUCCEEDED(rv)) {
+ mOwner->GetAttributes(attributes);
+ mOwner->GetParameters(params);
+ } else {
+ MOZ_ASSERT(false, "Failed to get tag type.");
+ }
+
+ mCachedParamLength = attributes.Length() + 1 + params.Length();
+
+ // We add an extra entry "PARAM" as a separator between the attribute
+ // and param values, but we don't count it if there are no <param> entries.
+ // Legacy behavior quirk.
+ uint32_t quirkParamLength = params.Length() ?
+ mCachedParamLength : attributes.Length();
+
+ mCachedParamNames = (char**)moz_xmalloc(sizeof(char*) * mCachedParamLength);
+ mCachedParamValues = (char**)moz_xmalloc(sizeof(char*) * mCachedParamLength);
+
+ for (uint32_t i = 0; i < attributes.Length(); i++) {
+ mCachedParamNames[i] = ToNewUTF8String(attributes[i].mName);
+ mCachedParamValues[i] = ToNewUTF8String(attributes[i].mValue);
+ }
+
+ // Android expects and empty string instead of null.
+ mCachedParamNames[attributes.Length()] = ToNewUTF8String(NS_LITERAL_STRING("PARAM"));
+ #ifdef MOZ_WIDGET_ANDROID
+ mCachedParamValues[attributes.Length()] = ToNewUTF8String(NS_LITERAL_STRING(""));
+ #else
+ mCachedParamValues[attributes.Length()] = nullptr;
+ #endif
+
+ for (uint32_t i = 0, pos = attributes.Length() + 1; i < params.Length(); i ++) {
+ mCachedParamNames[pos] = ToNewUTF8String(params[i].mName);
+ mCachedParamValues[pos] = ToNewUTF8String(params[i].mValue);
+ pos++;
+ }
+
+ int32_t mode;
+ const char* mimetype;
+ NPError error = NPERR_GENERIC_ERROR;
+
+ GetMode(&mode);
+ GetMIMEType(&mimetype);
+
+ CheckJavaC2PJSObjectQuirk(quirkParamLength, mCachedParamNames, mCachedParamValues);
+
+ bool oldVal = mInPluginInitCall;
+ mInPluginInitCall = true;
+
+ // Need this on the stack before calling NPP_New otherwise some callbacks that
+ // the plugin may make could fail (NPN_HasProperty, for example).
+ NPPAutoPusher autopush(&mNPP);
+
+ if (!mPlugin)
+ return NS_ERROR_FAILURE;
+
+ PluginLibrary* library = mPlugin->GetLibrary();
+ if (!library)
+ return NS_ERROR_FAILURE;
+
+ // Mark this instance as running before calling NPP_New because the plugin may
+ // call other NPAPI functions, like NPN_GetURLNotify, that assume this is set
+ // before returning. If the plugin returns failure, we'll clear it out below.
+ mRunning = RUNNING;
+
+ nsresult newResult = library->NPP_New((char*)mimetype, &mNPP, (uint16_t)mode,
+ quirkParamLength, mCachedParamNames,
+ mCachedParamValues, nullptr, &error);
+ mInPluginInitCall = oldVal;
+
+ NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
+ ("NPP New called: this=%p, npp=%p, mime=%s, mode=%d, argc=%d, return=%d\n",
+ this, &mNPP, mimetype, mode, quirkParamLength, error));
+
+ if (NS_FAILED(newResult) || error != NPERR_NO_ERROR) {
+ mRunning = DESTROYED;
+ nsJSNPRuntime::OnPluginDestroy(&mNPP);
+ return NS_ERROR_FAILURE;
+ }
+
+ return newResult;
+}
+
+nsresult nsNPAPIPluginInstance::SetWindow(NPWindow* window)
+{
+ // NPAPI plugins don't want a SetWindow(nullptr).
+ if (!window || RUNNING != mRunning)
+ return NS_OK;
+
+#if MOZ_WIDGET_GTK
+ // bug 108347, flash plugin on linux doesn't like window->width <=
+ // 0, but Java needs wants this call.
+ if (window && window->type == NPWindowTypeWindow &&
+ (window->width <= 0 || window->height <= 0) &&
+ (nsPluginHost::GetSpecialType(nsDependentCString(mMIMEType)) !=
+ nsPluginHost::eSpecialType_Java)) {
+ return NS_OK;
+ }
+#endif
+
+ if (!mPlugin || !mPlugin->GetLibrary())
+ return NS_ERROR_FAILURE;
+
+ NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
+
+ if (pluginFunctions->setwindow) {
+ PluginDestructionGuard guard(this);
+
+ // XXX Turns out that NPPluginWindow and NPWindow are structurally
+ // identical (on purpose!), so there's no need to make a copy.
+
+ PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::SetWindow (about to call it) this=%p\n",this));
+
+ bool oldVal = mInPluginInitCall;
+ mInPluginInitCall = true;
+
+ NPPAutoPusher nppPusher(&mNPP);
+
+ NPError error;
+ NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->setwindow)(&mNPP, (NPWindow*)window), this,
+ NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
+ // 'error' is only used if this is a logging-enabled build.
+ // That is somewhat complex to check, so we just use "unused"
+ // to suppress any compiler warnings in build configurations
+ // where the logging is a no-op.
+ mozilla::Unused << error;
+
+ mInPluginInitCall = oldVal;
+
+ NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
+ ("NPP SetWindow called: this=%p, [x=%d,y=%d,w=%d,h=%d], clip[t=%d,b=%d,l=%d,r=%d], return=%d\n",
+ this, window->x, window->y, window->width, window->height,
+ window->clipRect.top, window->clipRect.bottom, window->clipRect.left, window->clipRect.right, error));
+ }
+ return NS_OK;
+}
+
+nsresult
+nsNPAPIPluginInstance::NewStreamFromPlugin(const char* type, const char* target,
+ nsIOutputStream* *result)
+{
+ nsPluginStreamToFile* stream = new nsPluginStreamToFile(target, mOwner);
+ return stream->QueryInterface(kIOutputStreamIID, (void**)result);
+}
+
+nsresult
+nsNPAPIPluginInstance::NewStreamListener(const char* aURL, void* notifyData,
+ nsNPAPIPluginStreamListener** listener)
+{
+ RefPtr<nsNPAPIPluginStreamListener> sl = new nsNPAPIPluginStreamListener(this, notifyData, aURL);
+
+ mStreamListeners.AppendElement(sl);
+
+ sl.forget(listener);
+
+ return NS_OK;
+}
+
+nsresult nsNPAPIPluginInstance::Print(NPPrint* platformPrint)
+{
+ NS_ENSURE_TRUE(platformPrint, NS_ERROR_NULL_POINTER);
+
+ PluginDestructionGuard guard(this);
+
+ if (!mPlugin || !mPlugin->GetLibrary())
+ return NS_ERROR_FAILURE;
+
+ NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
+
+ NPPrint* thePrint = (NPPrint *)platformPrint;
+
+ // to be compatible with the older SDK versions and to match what
+ // NPAPI and other browsers do, overwrite |window.type| field with one
+ // more copy of |platformPrint|. See bug 113264
+ uint16_t sdkmajorversion = (pluginFunctions->version & 0xff00)>>8;
+ uint16_t sdkminorversion = pluginFunctions->version & 0x00ff;
+ if ((sdkmajorversion == 0) && (sdkminorversion < 11)) {
+ // Let's copy platformPrint bytes over to where it was supposed to be
+ // in older versions -- four bytes towards the beginning of the struct
+ // but we should be careful about possible misalignments
+ if (sizeof(NPWindowType) >= sizeof(void *)) {
+ void* source = thePrint->print.embedPrint.platformPrint;
+ void** destination = (void **)&(thePrint->print.embedPrint.window.type);
+ *destination = source;
+ } else {
+ NS_ERROR("Incompatible OS for assignment");
+ }
+ }
+
+ if (pluginFunctions->print)
+ NS_TRY_SAFE_CALL_VOID((*pluginFunctions->print)(&mNPP, thePrint), this,
+ NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
+
+ NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
+ ("NPP PrintProc called: this=%p, pDC=%p, [x=%d,y=%d,w=%d,h=%d], clip[t=%d,b=%d,l=%d,r=%d]\n",
+ this,
+ platformPrint->print.embedPrint.platformPrint,
+ platformPrint->print.embedPrint.window.x,
+ platformPrint->print.embedPrint.window.y,
+ platformPrint->print.embedPrint.window.width,
+ platformPrint->print.embedPrint.window.height,
+ platformPrint->print.embedPrint.window.clipRect.top,
+ platformPrint->print.embedPrint.window.clipRect.bottom,
+ platformPrint->print.embedPrint.window.clipRect.left,
+ platformPrint->print.embedPrint.window.clipRect.right));
+
+ return NS_OK;
+}
+
+nsresult nsNPAPIPluginInstance::HandleEvent(void* event, int16_t* result,
+ NSPluginCallReentry aSafeToReenterGecko)
+{
+ if (RUNNING != mRunning)
+ return NS_OK;
+
+ PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
+
+ if (!event)
+ return NS_ERROR_FAILURE;
+
+ PluginDestructionGuard guard(this);
+
+ if (!mPlugin || !mPlugin->GetLibrary())
+ return NS_ERROR_FAILURE;
+
+ NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
+
+ int16_t tmpResult = kNPEventNotHandled;
+
+ if (pluginFunctions->event) {
+#ifdef XP_MACOSX
+ mCurrentPluginEvent = event;
+#endif
+#if defined(XP_WIN)
+ NS_TRY_SAFE_CALL_RETURN(tmpResult, (*pluginFunctions->event)(&mNPP, event), this,
+ aSafeToReenterGecko);
+#else
+ MAIN_THREAD_JNI_REF_GUARD;
+ tmpResult = (*pluginFunctions->event)(&mNPP, event);
+#endif
+ NPP_PLUGIN_LOG(PLUGIN_LOG_NOISY,
+ ("NPP HandleEvent called: this=%p, npp=%p, event=%p, return=%d\n",
+ this, &mNPP, event, tmpResult));
+
+ if (result)
+ *result = tmpResult;
+#ifdef XP_MACOSX
+ mCurrentPluginEvent = nullptr;
+#endif
+ }
+
+ return NS_OK;
+}
+
+nsresult nsNPAPIPluginInstance::GetValueFromPlugin(NPPVariable variable, void* value)
+{
+ if (!mPlugin || !mPlugin->GetLibrary())
+ return NS_ERROR_FAILURE;
+
+ NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
+
+ nsresult rv = NS_ERROR_FAILURE;
+
+ if (pluginFunctions->getvalue && RUNNING == mRunning) {
+ PluginDestructionGuard guard(this);
+
+ NPError pluginError = NPERR_GENERIC_ERROR;
+ NS_TRY_SAFE_CALL_RETURN(pluginError, (*pluginFunctions->getvalue)(&mNPP, variable, value), this,
+ NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
+ NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
+ ("NPP GetValue called: this=%p, npp=%p, var=%d, value=%d, return=%d\n",
+ this, &mNPP, variable, value, pluginError));
+
+ if (pluginError == NPERR_NO_ERROR) {
+ rv = NS_OK;
+ }
+ }
+
+ return rv;
+}
+
+nsNPAPIPlugin* nsNPAPIPluginInstance::GetPlugin()
+{
+ return mPlugin;
+}
+
+nsresult nsNPAPIPluginInstance::GetNPP(NPP* aNPP)
+{
+ if (aNPP)
+ *aNPP = &mNPP;
+ else
+ return NS_ERROR_NULL_POINTER;
+
+ return NS_OK;
+}
+
+NPError nsNPAPIPluginInstance::SetWindowless(bool aWindowless)
+{
+ mWindowless = aWindowless;
+
+ if (mMIMEType) {
+ // bug 558434 - Prior to 3.6.4, we assumed windowless was transparent.
+ // Silverlight apparently relied on this quirk, so we default to
+ // transparent unless they specify otherwise after setting the windowless
+ // property. (Last tested version: sl 4.0).
+ // Changes to this code should be matched with changes in
+ // PluginInstanceChild::InitQuirksMode.
+ if (nsPluginHost::GetSpecialType(nsDependentCString(mMIMEType)) ==
+ nsPluginHost::eSpecialType_Silverlight) {
+ mTransparent = true;
+ }
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+NPError nsNPAPIPluginInstance::SetTransparent(bool aTransparent)
+{
+ mTransparent = aTransparent;
+ return NPERR_NO_ERROR;
+}
+
+NPError nsNPAPIPluginInstance::SetUsesDOMForCursor(bool aUsesDOMForCursor)
+{
+ mUsesDOMForCursor = aUsesDOMForCursor;
+ return NPERR_NO_ERROR;
+}
+
+bool
+nsNPAPIPluginInstance::UsesDOMForCursor()
+{
+ return mUsesDOMForCursor;
+}
+
+void nsNPAPIPluginInstance::SetDrawingModel(NPDrawingModel aModel)
+{
+ mDrawingModel = aModel;
+}
+
+void nsNPAPIPluginInstance::RedrawPlugin()
+{
+ mOwner->RedrawPlugin();
+}
+
+#if defined(XP_MACOSX)
+void nsNPAPIPluginInstance::SetEventModel(NPEventModel aModel)
+{
+ // the event model needs to be set for the object frame immediately
+ if (!mOwner) {
+ NS_WARNING("Trying to set event model without a plugin instance owner!");
+ return;
+ }
+
+ mOwner->SetEventModel(aModel);
+}
+#endif
+
+#if defined(MOZ_WIDGET_ANDROID)
+
+static void SendLifecycleEvent(nsNPAPIPluginInstance* aInstance, uint32_t aAction)
+{
+ ANPEvent event;
+ event.inSize = sizeof(ANPEvent);
+ event.eventType = kLifecycle_ANPEventType;
+ event.data.lifecycle.action = aAction;
+ aInstance->HandleEvent(&event, nullptr);
+}
+
+void nsNPAPIPluginInstance::NotifyForeground(bool aForeground)
+{
+ PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::SetForeground this=%p\n foreground=%d",this, aForeground));
+ if (RUNNING != mRunning)
+ return;
+
+ SendLifecycleEvent(this, aForeground ? kResume_ANPLifecycleAction : kPause_ANPLifecycleAction);
+}
+
+void nsNPAPIPluginInstance::NotifyOnScreen(bool aOnScreen)
+{
+ PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::SetOnScreen this=%p\n onScreen=%d",this, aOnScreen));
+ if (RUNNING != mRunning || mOnScreen == aOnScreen)
+ return;
+
+ mOnScreen = aOnScreen;
+ SendLifecycleEvent(this, aOnScreen ? kOnScreen_ANPLifecycleAction : kOffScreen_ANPLifecycleAction);
+}
+
+void nsNPAPIPluginInstance::MemoryPressure()
+{
+ PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::MemoryPressure this=%p\n",this));
+ if (RUNNING != mRunning)
+ return;
+
+ SendLifecycleEvent(this, kFreeMemory_ANPLifecycleAction);
+}
+
+void nsNPAPIPluginInstance::NotifyFullScreen(bool aFullScreen)
+{
+ PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::NotifyFullScreen this=%p\n",this));
+
+ if (RUNNING != mRunning || mFullScreen == aFullScreen)
+ return;
+
+ mFullScreen = aFullScreen;
+ SendLifecycleEvent(this, mFullScreen ? kEnterFullScreen_ANPLifecycleAction : kExitFullScreen_ANPLifecycleAction);
+
+ if (mFullScreen && mFullScreenOrientation != dom::eScreenOrientation_None) {
+ java::GeckoAppShell::LockScreenOrientation(mFullScreenOrientation);
+ }
+}
+
+void nsNPAPIPluginInstance::NotifySize(nsIntSize size)
+{
+ if (kOpenGL_ANPDrawingModel != GetANPDrawingModel() ||
+ size == mCurrentSize)
+ return;
+
+ mCurrentSize = size;
+
+ ANPEvent event;
+ event.inSize = sizeof(ANPEvent);
+ event.eventType = kDraw_ANPEventType;
+ event.data.draw.model = kOpenGL_ANPDrawingModel;
+ event.data.draw.data.surfaceSize.width = size.width;
+ event.data.draw.data.surfaceSize.height = size.height;
+
+ HandleEvent(&event, nullptr);
+}
+
+void nsNPAPIPluginInstance::SetANPDrawingModel(uint32_t aModel)
+{
+ mANPDrawingModel = aModel;
+}
+
+void* nsNPAPIPluginInstance::GetJavaSurface()
+{
+ void* surface = nullptr;
+ nsresult rv = GetValueFromPlugin(kJavaSurface_ANPGetValue, &surface);
+ if (NS_FAILED(rv))
+ return nullptr;
+
+ return surface;
+}
+
+void nsNPAPIPluginInstance::PostEvent(void* event)
+{
+ PluginEventRunnable *r = new PluginEventRunnable(this, (ANPEvent*)event);
+ mPostedEvents.AppendElement(RefPtr<PluginEventRunnable>(r));
+
+ NS_DispatchToMainThread(r);
+}
+
+void nsNPAPIPluginInstance::SetFullScreenOrientation(uint32_t orientation)
+{
+ if (mFullScreenOrientation == orientation)
+ return;
+
+ uint32_t oldOrientation = mFullScreenOrientation;
+ mFullScreenOrientation = orientation;
+
+ if (mFullScreen) {
+ // We're already fullscreen so immediately apply the orientation change
+
+ if (mFullScreenOrientation != dom::eScreenOrientation_None) {
+ java::GeckoAppShell::LockScreenOrientation(mFullScreenOrientation);
+ } else if (oldOrientation != dom::eScreenOrientation_None) {
+ // We applied an orientation when we entered fullscreen, but
+ // we don't want it anymore
+ java::GeckoAppShell::UnlockScreenOrientation();
+ }
+ }
+}
+
+void nsNPAPIPluginInstance::PopPostedEvent(PluginEventRunnable* r)
+{
+ mPostedEvents.RemoveElement(r);
+}
+
+void nsNPAPIPluginInstance::SetWakeLock(bool aLocked)
+{
+ if (aLocked == mWakeLocked)
+ return;
+
+ mWakeLocked = aLocked;
+ hal::ModifyWakeLock(NS_LITERAL_STRING("screen"),
+ mWakeLocked ? hal::WAKE_LOCK_ADD_ONE : hal::WAKE_LOCK_REMOVE_ONE,
+ hal::WAKE_LOCK_NO_CHANGE);
+}
+
+GLContext* nsNPAPIPluginInstance::GLContext()
+{
+ if (!EnsureGLContext())
+ return nullptr;
+
+ return sPluginContext;
+}
+
+already_AddRefed<AndroidSurfaceTexture> nsNPAPIPluginInstance::CreateSurfaceTexture()
+{
+ if (!EnsureGLContext())
+ return nullptr;
+
+ GLuint texture = TexturePoolOGL::AcquireTexture();
+ if (!texture)
+ return nullptr;
+
+ RefPtr<AndroidSurfaceTexture> surface = AndroidSurfaceTexture::Create(TexturePoolOGL::GetGLContext(),
+ texture);
+ if (!surface) {
+ return nullptr;
+ }
+
+ nsCOMPtr<nsIRunnable> frameCallback = NewRunnableMethod(this, &nsNPAPIPluginInstance::OnSurfaceTextureFrameAvailable);
+ surface->SetFrameAvailableCallback(frameCallback);
+ return surface.forget();
+}
+
+void nsNPAPIPluginInstance::OnSurfaceTextureFrameAvailable()
+{
+ if (mRunning == RUNNING && mOwner)
+ mOwner->Recomposite();
+}
+
+void* nsNPAPIPluginInstance::AcquireContentWindow()
+{
+ if (!mContentSurface) {
+ mContentSurface = CreateSurfaceTexture();
+
+ if (!mContentSurface)
+ return nullptr;
+ }
+
+ return mContentSurface->NativeWindow();
+}
+
+AndroidSurfaceTexture*
+nsNPAPIPluginInstance::AsSurfaceTexture()
+{
+ if (!mContentSurface)
+ return nullptr;
+
+ return mContentSurface;
+}
+
+void* nsNPAPIPluginInstance::AcquireVideoWindow()
+{
+ RefPtr<AndroidSurfaceTexture> surface = CreateSurfaceTexture();
+ if (!surface) {
+ return nullptr;
+ }
+
+ VideoInfo* info = new VideoInfo(surface);
+
+ void* window = info->mSurfaceTexture->NativeWindow();
+ mVideos.insert(std::pair<void*, VideoInfo*>(window, info));
+
+ return window;
+}
+
+void nsNPAPIPluginInstance::ReleaseVideoWindow(void* window)
+{
+ std::map<void*, VideoInfo*>::iterator it = mVideos.find(window);
+ if (it == mVideos.end())
+ return;
+
+ delete it->second;
+ mVideos.erase(window);
+}
+
+void nsNPAPIPluginInstance::SetVideoDimensions(void* window, gfxRect aDimensions)
+{
+ std::map<void*, VideoInfo*>::iterator it;
+
+ it = mVideos.find(window);
+ if (it == mVideos.end())
+ return;
+
+ it->second->mDimensions = aDimensions;
+}
+
+void nsNPAPIPluginInstance::GetVideos(nsTArray<VideoInfo*>& aVideos)
+{
+ std::map<void*, VideoInfo*>::iterator it;
+ for (it = mVideos.begin(); it != mVideos.end(); it++)
+ aVideos.AppendElement(it->second);
+}
+
+nsNPAPIPluginInstance* nsNPAPIPluginInstance::GetFromNPP(NPP npp)
+{
+ std::map<NPP, nsNPAPIPluginInstance*>::iterator it;
+
+ it = sPluginNPPMap.find(npp);
+ if (it == sPluginNPPMap.end())
+ return nullptr;
+
+ return it->second;
+}
+
+#endif
+
+nsresult nsNPAPIPluginInstance::GetDrawingModel(int32_t* aModel)
+{
+ *aModel = (int32_t)mDrawingModel;
+ return NS_OK;
+}
+
+nsresult nsNPAPIPluginInstance::IsRemoteDrawingCoreAnimation(bool* aDrawing)
+{
+#ifdef XP_MACOSX
+ if (!mPlugin)
+ return NS_ERROR_FAILURE;
+
+ PluginLibrary* library = mPlugin->GetLibrary();
+ if (!library)
+ return NS_ERROR_FAILURE;
+
+ return library->IsRemoteDrawingCoreAnimation(&mNPP, aDrawing);
+#else
+ return NS_ERROR_FAILURE;
+#endif
+}
+
+nsresult
+nsNPAPIPluginInstance::ContentsScaleFactorChanged(double aContentsScaleFactor)
+{
+#if defined(XP_MACOSX) || defined(XP_WIN)
+ if (!mPlugin)
+ return NS_ERROR_FAILURE;
+
+ PluginLibrary* library = mPlugin->GetLibrary();
+ if (!library)
+ return NS_ERROR_FAILURE;
+
+ // We only need to call this if the plugin is running OOP.
+ if (!library->IsOOP())
+ return NS_OK;
+
+ return library->ContentsScaleFactorChanged(&mNPP, aContentsScaleFactor);
+#else
+ return NS_ERROR_FAILURE;
+#endif
+}
+
+nsresult
+nsNPAPIPluginInstance::CSSZoomFactorChanged(float aCSSZoomFactor)
+{
+ if (RUNNING != mRunning)
+ return NS_OK;
+
+ PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance informing plugin of CSS Zoom Factor change this=%p\n",this));
+
+ if (!mPlugin || !mPlugin->GetLibrary())
+ return NS_ERROR_FAILURE;
+
+ NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
+
+ if (!pluginFunctions->setvalue)
+ return NS_ERROR_FAILURE;
+
+ PluginDestructionGuard guard(this);
+
+ NPError error;
+ double value = static_cast<double>(aCSSZoomFactor);
+ NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->setvalue)(&mNPP, NPNVCSSZoomFactor, &value), this,
+ NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
+ return (error == NPERR_NO_ERROR) ? NS_OK : NS_ERROR_FAILURE;
+}
+
+nsresult
+nsNPAPIPluginInstance::GetJSObject(JSContext *cx, JSObject** outObject)
+{
+ if (mHaveJavaC2PJSObjectQuirk) {
+ return NS_ERROR_FAILURE;
+ }
+
+ NPObject *npobj = nullptr;
+ nsresult rv = GetValueFromPlugin(NPPVpluginScriptableNPObject, &npobj);
+ if (NS_FAILED(rv) || !npobj)
+ return NS_ERROR_FAILURE;
+
+ *outObject = nsNPObjWrapper::GetNewOrUsed(&mNPP, cx, npobj);
+
+ _releaseobject(npobj);
+
+ return NS_OK;
+}
+
+void
+nsNPAPIPluginInstance::SetCached(bool aCache)
+{
+ mCached = aCache;
+}
+
+bool
+nsNPAPIPluginInstance::ShouldCache()
+{
+ return mCached;
+}
+
+nsresult
+nsNPAPIPluginInstance::IsWindowless(bool* isWindowless)
+{
+#if defined(MOZ_WIDGET_ANDROID) || defined(XP_MACOSX)
+ // All OS X plugins are windowless.
+ // On android, pre-honeycomb, all plugins are treated as windowless.
+ *isWindowless = true;
+#else
+ *isWindowless = mWindowless;
+#endif
+ return NS_OK;
+}
+
+class MOZ_STACK_CLASS AutoPluginLibraryCall
+{
+public:
+ explicit AutoPluginLibraryCall(nsNPAPIPluginInstance* aThis)
+ : mThis(aThis), mGuard(aThis), mLibrary(nullptr)
+ {
+ nsNPAPIPlugin* plugin = mThis->GetPlugin();
+ if (plugin)
+ mLibrary = plugin->GetLibrary();
+ }
+ explicit operator bool() { return !!mLibrary; }
+ PluginLibrary* operator->() { return mLibrary; }
+
+private:
+ nsNPAPIPluginInstance* mThis;
+ PluginDestructionGuard mGuard;
+ PluginLibrary* mLibrary;
+};
+
+nsresult
+nsNPAPIPluginInstance::AsyncSetWindow(NPWindow* window)
+{
+ if (RUNNING != mRunning)
+ return NS_OK;
+
+ AutoPluginLibraryCall library(this);
+ if (!library)
+ return NS_ERROR_FAILURE;
+
+ return library->AsyncSetWindow(&mNPP, window);
+}
+
+nsresult
+nsNPAPIPluginInstance::GetImageContainer(ImageContainer**aContainer)
+{
+ *aContainer = nullptr;
+
+ if (RUNNING != mRunning)
+ return NS_OK;
+
+ AutoPluginLibraryCall library(this);
+ return !library ? NS_ERROR_FAILURE : library->GetImageContainer(&mNPP, aContainer);
+}
+
+nsresult
+nsNPAPIPluginInstance::GetImageSize(nsIntSize* aSize)
+{
+ *aSize = nsIntSize(0, 0);
+
+ if (RUNNING != mRunning)
+ return NS_OK;
+
+ AutoPluginLibraryCall library(this);
+ return !library ? NS_ERROR_FAILURE : library->GetImageSize(&mNPP, aSize);
+}
+
+#if defined(XP_WIN)
+nsresult
+nsNPAPIPluginInstance::GetScrollCaptureContainer(ImageContainer**aContainer)
+{
+ *aContainer = nullptr;
+
+ if (RUNNING != mRunning)
+ return NS_OK;
+
+ AutoPluginLibraryCall library(this);
+ return !library ? NS_ERROR_FAILURE : library->GetScrollCaptureContainer(&mNPP, aContainer);
+}
+#endif
+
+nsresult
+nsNPAPIPluginInstance::HandledWindowedPluginKeyEvent(
+ const NativeEventData& aKeyEventData,
+ bool aIsConsumed)
+{
+ if (NS_WARN_IF(!mPlugin)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ PluginLibrary* library = mPlugin->GetLibrary();
+ if (NS_WARN_IF(!library)) {
+ return NS_ERROR_FAILURE;
+ }
+ return library->HandledWindowedPluginKeyEvent(&mNPP, aKeyEventData,
+ aIsConsumed);
+}
+
+void
+nsNPAPIPluginInstance::DidComposite()
+{
+ if (RUNNING != mRunning)
+ return;
+
+ AutoPluginLibraryCall library(this);
+ library->DidComposite(&mNPP);
+}
+
+nsresult
+nsNPAPIPluginInstance::NotifyPainted(void)
+{
+ NS_NOTREACHED("Dead code, shouldn't be called.");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
+nsNPAPIPluginInstance::GetIsOOP(bool* aIsAsync)
+{
+ AutoPluginLibraryCall library(this);
+ if (!library)
+ return NS_ERROR_FAILURE;
+
+ *aIsAsync = library->IsOOP();
+ return NS_OK;
+}
+
+nsresult
+nsNPAPIPluginInstance::SetBackgroundUnknown()
+{
+ if (RUNNING != mRunning)
+ return NS_OK;
+
+ AutoPluginLibraryCall library(this);
+ if (!library)
+ return NS_ERROR_FAILURE;
+
+ return library->SetBackgroundUnknown(&mNPP);
+}
+
+nsresult
+nsNPAPIPluginInstance::BeginUpdateBackground(nsIntRect* aRect,
+ DrawTarget** aDrawTarget)
+{
+ if (RUNNING != mRunning)
+ return NS_OK;
+
+ AutoPluginLibraryCall library(this);
+ if (!library)
+ return NS_ERROR_FAILURE;
+
+ return library->BeginUpdateBackground(&mNPP, *aRect, aDrawTarget);
+}
+
+nsresult
+nsNPAPIPluginInstance::EndUpdateBackground(nsIntRect* aRect)
+{
+ if (RUNNING != mRunning)
+ return NS_OK;
+
+ AutoPluginLibraryCall library(this);
+ if (!library)
+ return NS_ERROR_FAILURE;
+
+ return library->EndUpdateBackground(&mNPP, *aRect);
+}
+
+nsresult
+nsNPAPIPluginInstance::IsTransparent(bool* isTransparent)
+{
+ *isTransparent = mTransparent;
+ return NS_OK;
+}
+
+nsresult
+nsNPAPIPluginInstance::GetFormValue(nsAString& aValue)
+{
+ aValue.Truncate();
+
+ char *value = nullptr;
+ nsresult rv = GetValueFromPlugin(NPPVformValue, &value);
+ if (NS_FAILED(rv) || !value)
+ return NS_ERROR_FAILURE;
+
+ CopyUTF8toUTF16(value, aValue);
+
+ // NPPVformValue allocates with NPN_MemAlloc(), which uses
+ // nsMemory.
+ free(value);
+
+ return NS_OK;
+}
+
+nsresult
+nsNPAPIPluginInstance::PushPopupsEnabledState(bool aEnabled)
+{
+ nsCOMPtr<nsPIDOMWindowOuter> window = GetDOMWindow();
+ if (!window)
+ return NS_ERROR_FAILURE;
+
+ PopupControlState oldState =
+ window->PushPopupControlState(aEnabled ? openAllowed : openAbused,
+ true);
+
+ if (!mPopupStates.AppendElement(oldState)) {
+ // Appending to our state stack failed, pop what we just pushed.
+ window->PopPopupControlState(oldState);
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+nsresult
+nsNPAPIPluginInstance::PopPopupsEnabledState()
+{
+ int32_t last = mPopupStates.Length() - 1;
+
+ if (last < 0) {
+ // Nothing to pop.
+ return NS_OK;
+ }
+
+ nsCOMPtr<nsPIDOMWindowOuter> window = GetDOMWindow();
+ if (!window)
+ return NS_ERROR_FAILURE;
+
+ PopupControlState &oldState = mPopupStates[last];
+
+ window->PopPopupControlState(oldState);
+
+ mPopupStates.RemoveElementAt(last);
+
+ return NS_OK;
+}
+
+nsresult
+nsNPAPIPluginInstance::GetPluginAPIVersion(uint16_t* version)
+{
+ NS_ENSURE_ARG_POINTER(version);
+
+ if (!mPlugin)
+ return NS_ERROR_FAILURE;
+
+ if (!mPlugin->GetLibrary())
+ return NS_ERROR_FAILURE;
+
+ NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
+
+ *version = pluginFunctions->version;
+
+ return NS_OK;
+}
+
+nsresult
+nsNPAPIPluginInstance::PrivateModeStateChanged(bool enabled)
+{
+ if (RUNNING != mRunning)
+ return NS_OK;
+
+ PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance informing plugin of private mode state change this=%p\n",this));
+
+ if (!mPlugin || !mPlugin->GetLibrary())
+ return NS_ERROR_FAILURE;
+
+ NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
+
+ if (!pluginFunctions->setvalue)
+ return NS_ERROR_FAILURE;
+
+ PluginDestructionGuard guard(this);
+
+ NPError error;
+ NPBool value = static_cast<NPBool>(enabled);
+ NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->setvalue)(&mNPP, NPNVprivateModeBool, &value), this,
+ NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
+ return (error == NPERR_NO_ERROR) ? NS_OK : NS_ERROR_FAILURE;
+}
+
+nsresult
+nsNPAPIPluginInstance::IsPrivateBrowsing(bool* aEnabled)
+{
+ if (!mOwner)
+ return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDocument> doc;
+ mOwner->GetDocument(getter_AddRefs(doc));
+ NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
+
+ nsCOMPtr<nsPIDOMWindowOuter> domwindow = doc->GetWindow();
+ NS_ENSURE_TRUE(domwindow, NS_ERROR_FAILURE);
+
+ nsCOMPtr<nsIDocShell> docShell = domwindow->GetDocShell();
+ nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
+ *aEnabled = (loadContext && loadContext->UsePrivateBrowsing());
+ return NS_OK;
+}
+
+static void
+PluginTimerCallback(nsITimer *aTimer, void *aClosure)
+{
+ nsNPAPITimer* t = (nsNPAPITimer*)aClosure;
+ NPP npp = t->npp;
+ uint32_t id = t->id;
+
+ PLUGIN_LOG(PLUGIN_LOG_NOISY, ("nsNPAPIPluginInstance running plugin timer callback this=%p\n", npp->ndata));
+
+ MAIN_THREAD_JNI_REF_GUARD;
+ // Some plugins (Flash on Android) calls unscheduletimer
+ // from this callback.
+ t->inCallback = true;
+ (*(t->callback))(npp, id);
+ t->inCallback = false;
+
+ // Make sure we still have an instance and the timer is still alive
+ // after the callback.
+ nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance*)npp->ndata;
+ if (!inst || !inst->TimerWithID(id, nullptr))
+ return;
+
+ // use UnscheduleTimer to clean up if this is a one-shot timer
+ uint32_t timerType;
+ t->timer->GetType(&timerType);
+ if (t->needUnschedule || timerType == nsITimer::TYPE_ONE_SHOT)
+ inst->UnscheduleTimer(id);
+}
+
+nsNPAPITimer*
+nsNPAPIPluginInstance::TimerWithID(uint32_t id, uint32_t* index)
+{
+ uint32_t len = mTimers.Length();
+ for (uint32_t i = 0; i < len; i++) {
+ if (mTimers[i]->id == id) {
+ if (index)
+ *index = i;
+ return mTimers[i];
+ }
+ }
+ return nullptr;
+}
+
+uint32_t
+nsNPAPIPluginInstance::ScheduleTimer(uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID))
+{
+ if (RUNNING != mRunning)
+ return 0;
+
+ nsNPAPITimer *newTimer = new nsNPAPITimer();
+
+ newTimer->inCallback = newTimer->needUnschedule = false;
+ newTimer->npp = &mNPP;
+
+ // generate ID that is unique to this instance
+ uint32_t uniqueID = mTimers.Length();
+ while ((uniqueID == 0) || TimerWithID(uniqueID, nullptr))
+ uniqueID++;
+ newTimer->id = uniqueID;
+
+ // create new xpcom timer, scheduled correctly
+ nsresult rv;
+ nsCOMPtr<nsITimer> xpcomTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
+ if (NS_FAILED(rv)) {
+ delete newTimer;
+ return 0;
+ }
+ const short timerType = (repeat ? (short)nsITimer::TYPE_REPEATING_SLACK : (short)nsITimer::TYPE_ONE_SHOT);
+ xpcomTimer->InitWithFuncCallback(PluginTimerCallback, newTimer, interval, timerType);
+ newTimer->timer = xpcomTimer;
+
+ // save callback function
+ newTimer->callback = timerFunc;
+
+ // add timer to timers array
+ mTimers.AppendElement(newTimer);
+
+ return newTimer->id;
+}
+
+void
+nsNPAPIPluginInstance::UnscheduleTimer(uint32_t timerID)
+{
+ // find the timer struct by ID
+ uint32_t index;
+ nsNPAPITimer* t = TimerWithID(timerID, &index);
+ if (!t)
+ return;
+
+ if (t->inCallback) {
+ t->needUnschedule = true;
+ return;
+ }
+
+ // cancel the timer
+ t->timer->Cancel();
+
+ // remove timer struct from array
+ mTimers.RemoveElementAt(index);
+
+ // delete timer
+ delete t;
+}
+
+NPBool
+nsNPAPIPluginInstance::ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
+ double *destX, double *destY, NPCoordinateSpace destSpace)
+{
+ if (mOwner) {
+ return mOwner->ConvertPoint(sourceX, sourceY, sourceSpace, destX, destY, destSpace);
+ }
+
+ return false;
+}
+
+nsresult
+nsNPAPIPluginInstance::GetDOMElement(nsIDOMElement* *result)
+{
+ if (!mOwner) {
+ *result = nullptr;
+ return NS_ERROR_FAILURE;
+ }
+
+ return mOwner->GetDOMElement(result);
+}
+
+nsresult
+nsNPAPIPluginInstance::InvalidateRect(NPRect *invalidRect)
+{
+ if (RUNNING != mRunning)
+ return NS_OK;
+
+ if (!mOwner)
+ return NS_ERROR_FAILURE;
+
+ return mOwner->InvalidateRect(invalidRect);
+}
+
+nsresult
+nsNPAPIPluginInstance::InvalidateRegion(NPRegion invalidRegion)
+{
+ if (RUNNING != mRunning)
+ return NS_OK;
+
+ if (!mOwner)
+ return NS_ERROR_FAILURE;
+
+ return mOwner->InvalidateRegion(invalidRegion);
+}
+
+nsresult
+nsNPAPIPluginInstance::GetMIMEType(const char* *result)
+{
+ if (!mMIMEType)
+ *result = "";
+ else
+ *result = mMIMEType;
+
+ return NS_OK;
+}
+
+nsPluginInstanceOwner*
+nsNPAPIPluginInstance::GetOwner()
+{
+ return mOwner;
+}
+
+void
+nsNPAPIPluginInstance::SetOwner(nsPluginInstanceOwner *aOwner)
+{
+ mOwner = aOwner;
+}
+
+nsresult
+nsNPAPIPluginInstance::AsyncSetWindow(NPWindow& window)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+void
+nsNPAPIPluginInstance::URLRedirectResponse(void* notifyData, NPBool allow)
+{
+ if (!notifyData) {
+ return;
+ }
+
+ uint32_t listenerCount = mStreamListeners.Length();
+ for (uint32_t i = 0; i < listenerCount; i++) {
+ nsNPAPIPluginStreamListener* currentListener = mStreamListeners[i];
+ if (currentListener->GetNotifyData() == notifyData) {
+ currentListener->URLRedirectResponse(allow);
+ }
+ }
+}
+
+NPError
+nsNPAPIPluginInstance::InitAsyncSurface(NPSize *size, NPImageFormat format,
+ void *initData, NPAsyncSurface *surface)
+{
+ if (mOwner) {
+ return mOwner->InitAsyncSurface(size, format, initData, surface);
+ }
+
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError
+nsNPAPIPluginInstance::FinalizeAsyncSurface(NPAsyncSurface *surface)
+{
+ if (mOwner) {
+ return mOwner->FinalizeAsyncSurface(surface);
+ }
+
+ return NPERR_GENERIC_ERROR;
+}
+
+void
+nsNPAPIPluginInstance::SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed)
+{
+ if (mOwner) {
+ mOwner->SetCurrentAsyncSurface(surface, changed);
+ }
+}
+
+class CarbonEventModelFailureEvent : public Runnable {
+public:
+ nsCOMPtr<nsIContent> mContent;
+
+ explicit CarbonEventModelFailureEvent(nsIContent* aContent)
+ : mContent(aContent)
+ {}
+
+ ~CarbonEventModelFailureEvent() {}
+
+ NS_IMETHOD Run();
+};
+
+NS_IMETHODIMP
+CarbonEventModelFailureEvent::Run()
+{
+ nsString type = NS_LITERAL_STRING("npapi-carbon-event-model-failure");
+ nsContentUtils::DispatchTrustedEvent(mContent->GetComposedDoc(), mContent,
+ type, true, true);
+ return NS_OK;
+}
+
+void
+nsNPAPIPluginInstance::CarbonNPAPIFailure()
+{
+ nsCOMPtr<nsIDOMElement> element;
+ GetDOMElement(getter_AddRefs(element));
+ if (!element) {
+ return;
+ }
+
+ nsCOMPtr<nsIContent> content(do_QueryInterface(element));
+ if (!content) {
+ return;
+ }
+
+ nsCOMPtr<nsIRunnable> e = new CarbonEventModelFailureEvent(content);
+ nsresult rv = NS_DispatchToCurrentThread(e);
+ if (NS_FAILED(rv)) {
+ NS_WARNING("Failed to dispatch CarbonEventModelFailureEvent.");
+ }
+}
+
+static bool
+GetJavaVersionFromMimetype(nsPluginTag* pluginTag, nsCString& version)
+{
+ for (uint32_t i = 0; i < pluginTag->MimeTypes().Length(); ++i) {
+ nsCString type = pluginTag->MimeTypes()[i];
+ nsAutoCString jpi("application/x-java-applet;jpi-version=");
+
+ int32_t idx = type.Find(jpi, false, 0, -1);
+ if (idx != 0) {
+ continue;
+ }
+
+ type.Cut(0, jpi.Length());
+ if (type.IsEmpty()) {
+ continue;
+ }
+
+ type.ReplaceChar('_', '.');
+ version = type;
+ return true;
+ }
+
+ return false;
+}
+
+void
+nsNPAPIPluginInstance::CheckJavaC2PJSObjectQuirk(uint16_t paramCount,
+ const char* const* paramNames,
+ const char* const* paramValues)
+{
+ if (!mMIMEType || !mPlugin) {
+ return;
+ }
+
+ nsPluginTagType tagtype;
+ nsresult rv = GetTagType(&tagtype);
+ if (NS_FAILED(rv) ||
+ (tagtype != nsPluginTagType_Applet)) {
+ return;
+ }
+
+ RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
+ if (!pluginHost) {
+ return;
+ }
+
+ nsPluginTag* pluginTag = pluginHost->TagForPlugin(mPlugin);
+ if (!pluginTag ||
+ !pluginTag->mIsJavaPlugin) {
+ return;
+ }
+
+ // check the params for "code" being present and non-empty
+ bool haveCodeParam = false;
+ bool isCodeParamEmpty = true;
+
+ for (uint16_t i = paramCount; i > 0; --i) {
+ if (PL_strcasecmp(paramNames[i - 1], "code") == 0) {
+ haveCodeParam = true;
+ if (strlen(paramValues[i - 1]) > 0) {
+ isCodeParamEmpty = false;
+ }
+ break;
+ }
+ }
+
+ // Due to the Java version being specified inconsistently across platforms
+ // check the version via the mimetype for choosing specific Java versions
+ nsCString javaVersion;
+ if (!GetJavaVersionFromMimetype(pluginTag, javaVersion)) {
+ return;
+ }
+
+ mozilla::Version version(javaVersion.get());
+
+ if (version >= "1.7.0.4") {
+ return;
+ }
+
+ if (!haveCodeParam && version >= "1.6.0.34" && version < "1.7") {
+ return;
+ }
+
+ if (haveCodeParam && !isCodeParamEmpty) {
+ return;
+ }
+
+ mHaveJavaC2PJSObjectQuirk = true;
+}
+
+double
+nsNPAPIPluginInstance::GetContentsScaleFactor()
+{
+ double scaleFactor = 1.0;
+ if (mOwner) {
+ mOwner->GetContentsScaleFactor(&scaleFactor);
+ }
+ return scaleFactor;
+}
+
+float
+nsNPAPIPluginInstance::GetCSSZoomFactor()
+{
+ float zoomFactor = 1.0;
+ if (mOwner) {
+ mOwner->GetCSSZoomFactor(&zoomFactor);
+ }
+ return zoomFactor;
+}
+
+nsresult
+nsNPAPIPluginInstance::GetRunID(uint32_t* aRunID)
+{
+ if (NS_WARN_IF(!aRunID)) {
+ return NS_ERROR_INVALID_POINTER;
+ }
+
+ if (NS_WARN_IF(!mPlugin)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ PluginLibrary* library = mPlugin->GetLibrary();
+ if (!library) {
+ return NS_ERROR_FAILURE;
+ }
+
+ return library->GetRunID(aRunID);
+}
+
+nsresult
+nsNPAPIPluginInstance::GetOrCreateAudioChannelAgent(nsIAudioChannelAgent** aAgent)
+{
+ if (!mAudioChannelAgent) {
+ nsresult rv;
+ mAudioChannelAgent = do_CreateInstance("@mozilla.org/audiochannelagent;1", &rv);
+ if (NS_WARN_IF(!mAudioChannelAgent)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ nsCOMPtr<nsPIDOMWindowOuter> window = GetDOMWindow();
+ if (NS_WARN_IF(!window)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ rv = mAudioChannelAgent->Init(window->GetCurrentInnerWindow(),
+ (int32_t)AudioChannelService::GetDefaultAudioChannel(),
+ this);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ }
+
+ nsCOMPtr<nsIAudioChannelAgent> agent = mAudioChannelAgent;
+ agent.forget(aAgent);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsNPAPIPluginInstance::WindowVolumeChanged(float aVolume, bool aMuted)
+{
+ // We just support mute/unmute
+ nsresult rv = SetMuted(aMuted);
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "SetMuted failed");
+ if (mMuted != aMuted) {
+ mMuted = aMuted;
+ AudioChannelService::AudibleState audible = aMuted ?
+ AudioChannelService::AudibleState::eNotAudible :
+ AudioChannelService::AudibleState::eAudible;
+ mAudioChannelAgent->NotifyStartedAudible(audible,
+ AudioChannelService::AudibleChangedReasons::eVolumeChanged);
+ }
+ return rv;
+}
+
+NS_IMETHODIMP
+nsNPAPIPluginInstance::WindowSuspendChanged(nsSuspendedTypes aSuspend)
+{
+ // It doesn't support suspended, so we just do something like mute/unmute.
+ WindowVolumeChanged(1.0, /* useless */
+ aSuspend != nsISuspendedTypes::NONE_SUSPENDED);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsNPAPIPluginInstance::WindowAudioCaptureChanged(bool aCapture)
+{
+ return NS_OK;
+}
+
+nsresult
+nsNPAPIPluginInstance::SetMuted(bool aIsMuted)
+{
+ if (RUNNING != mRunning)
+ return NS_OK;
+
+ PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance informing plugin of mute state change this=%p\n",this));
+
+ if (!mPlugin || !mPlugin->GetLibrary())
+ return NS_ERROR_FAILURE;
+
+ NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
+
+ if (!pluginFunctions->setvalue)
+ return NS_ERROR_FAILURE;
+
+ PluginDestructionGuard guard(this);
+
+ NPError error;
+ NPBool value = static_cast<NPBool>(aIsMuted);
+ NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->setvalue)(&mNPP, NPNVmuteAudioBool, &value), this,
+ NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
+ return (error == NPERR_NO_ERROR) ? NS_OK : NS_ERROR_FAILURE;
+}