michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/DebugOnly.h" michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: // For ScreenOrientation.h and Hal.h michael@0: #include "base/basictypes.h" michael@0: #endif michael@0: michael@0: #include "prlog.h" michael@0: #include "prmem.h" michael@0: #include "nscore.h" michael@0: #include "prenv.h" michael@0: michael@0: #include "nsNPAPIPluginInstance.h" michael@0: #include "nsNPAPIPlugin.h" michael@0: #include "nsNPAPIPluginStreamListener.h" michael@0: #include "nsPluginHost.h" michael@0: #include "nsPluginLogging.h" michael@0: #include "nsContentUtils.h" michael@0: #include "nsPluginInstanceOwner.h" michael@0: michael@0: #include "nsThreadUtils.h" michael@0: #include "nsIDOMElement.h" michael@0: #include "nsIDocument.h" michael@0: #include "nsIDocShell.h" michael@0: #include "nsIScriptGlobalObject.h" michael@0: #include "nsIScriptContext.h" michael@0: #include "nsDirectoryServiceDefs.h" michael@0: #include "nsJSNPRuntime.h" michael@0: #include "nsPluginStreamListenerPeer.h" michael@0: #include "nsSize.h" michael@0: #include "nsNetCID.h" michael@0: #include "nsIContent.h" michael@0: #include "nsVersionComparator.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "mozilla/unused.h" michael@0: #include "nsILoadContext.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: #include "ANPBase.h" michael@0: #include michael@0: #include "android_npapi.h" michael@0: #include "mozilla/Mutex.h" michael@0: #include "mozilla/CondVar.h" michael@0: #include "AndroidBridge.h" michael@0: #include "mozilla/dom/ScreenOrientation.h" michael@0: #include "mozilla/Hal.h" michael@0: #include "GLContextProvider.h" michael@0: #include "GLContext.h" michael@0: #include "TexturePoolOGL.h" michael@0: #include "GLSharedHandleHelpers.h" michael@0: michael@0: using namespace mozilla::gl; michael@0: michael@0: typedef nsNPAPIPluginInstance::VideoInfo VideoInfo; michael@0: michael@0: class PluginEventRunnable : public nsRunnable michael@0: { michael@0: public: michael@0: PluginEventRunnable(nsNPAPIPluginInstance* instance, ANPEvent* event) michael@0: : mInstance(instance), mEvent(*event), mCanceled(false) {} michael@0: michael@0: virtual nsresult Run() { michael@0: if (mCanceled) michael@0: return NS_OK; michael@0: michael@0: mInstance->HandleEvent(&mEvent, nullptr); michael@0: mInstance->PopPostedEvent(this); michael@0: return NS_OK; michael@0: } michael@0: michael@0: void Cancel() { mCanceled = true; } michael@0: private: michael@0: nsNPAPIPluginInstance* mInstance; michael@0: ANPEvent mEvent; michael@0: bool mCanceled; michael@0: }; michael@0: michael@0: static nsRefPtr sPluginContext = nullptr; michael@0: michael@0: static bool EnsureGLContext() michael@0: { michael@0: if (!sPluginContext) { michael@0: gfxIntSize dummySize(16, 16); michael@0: sPluginContext = GLContextProvider::CreateOffscreen(dummySize, michael@0: GLContext::SurfaceCaps::Any()); michael@0: } michael@0: michael@0: return sPluginContext != nullptr; michael@0: } michael@0: michael@0: class SharedPluginTexture MOZ_FINAL { michael@0: public: michael@0: NS_INLINE_DECL_REFCOUNTING(SharedPluginTexture) michael@0: michael@0: SharedPluginTexture() : mLock("SharedPluginTexture.mLock") michael@0: { michael@0: } michael@0: michael@0: nsNPAPIPluginInstance::TextureInfo Lock() michael@0: { michael@0: if (!EnsureGLContext()) { michael@0: mTextureInfo.mTexture = 0; michael@0: return mTextureInfo; michael@0: } michael@0: michael@0: if (!mTextureInfo.mTexture && sPluginContext->MakeCurrent()) { michael@0: sPluginContext->fGenTextures(1, &mTextureInfo.mTexture); michael@0: } michael@0: michael@0: mLock.Lock(); michael@0: return mTextureInfo; michael@0: } michael@0: michael@0: void Release(nsNPAPIPluginInstance::TextureInfo& aTextureInfo) michael@0: { michael@0: mTextureInfo = aTextureInfo; michael@0: mLock.Unlock(); michael@0: } michael@0: michael@0: SharedTextureHandle CreateSharedHandle() michael@0: { michael@0: MutexAutoLock lock(mLock); michael@0: michael@0: if (!EnsureGLContext()) michael@0: return 0; michael@0: michael@0: if (mTextureInfo.mWidth == 0 || mTextureInfo.mHeight == 0) michael@0: return 0; michael@0: michael@0: SharedTextureHandle handle = michael@0: gl::CreateSharedHandle(sPluginContext, michael@0: gl::SharedTextureShareType::SameProcess, michael@0: (void*)mTextureInfo.mTexture, michael@0: gl::SharedTextureBufferType::TextureID); michael@0: michael@0: // We want forget about this now, so delete the texture. Assigning it to zero michael@0: // ensures that we create a new one in Lock() michael@0: sPluginContext->fDeleteTextures(1, &mTextureInfo.mTexture); michael@0: mTextureInfo.mTexture = 0; michael@0: michael@0: return handle; michael@0: } michael@0: michael@0: private: michael@0: // Private destructor, to discourage deletion outside of Release(): michael@0: ~SharedPluginTexture() michael@0: { michael@0: } michael@0: michael@0: nsNPAPIPluginInstance::TextureInfo mTextureInfo; michael@0: michael@0: Mutex mLock; michael@0: }; michael@0: michael@0: static std::map sPluginNPPMap; michael@0: michael@0: #endif michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::plugins::parent; michael@0: using namespace mozilla::layers; michael@0: michael@0: static NS_DEFINE_IID(kIOutputStreamIID, NS_IOUTPUTSTREAM_IID); michael@0: michael@0: NS_IMPL_ISUPPORTS0(nsNPAPIPluginInstance) michael@0: michael@0: nsNPAPIPluginInstance::nsNPAPIPluginInstance() michael@0: : michael@0: mDrawingModel(kDefaultDrawingModel), michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: mANPDrawingModel(0), michael@0: mFullScreenOrientation(dom::eScreenOrientation_LandscapePrimary), michael@0: mWakeLocked(false), michael@0: mFullScreen(false), michael@0: mInverted(false), michael@0: #endif michael@0: mRunning(NOT_STARTED), michael@0: mWindowless(false), michael@0: mTransparent(false), michael@0: mCached(false), michael@0: mUsesDOMForCursor(false), michael@0: mInPluginInitCall(false), michael@0: mPlugin(nullptr), michael@0: mMIMEType(nullptr), michael@0: mOwner(nullptr), michael@0: mCurrentPluginEvent(nullptr) michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: , mOnScreen(true) michael@0: #endif michael@0: , mHaveJavaC2PJSObjectQuirk(false) michael@0: { michael@0: mNPP.pdata = nullptr; michael@0: mNPP.ndata = this; michael@0: michael@0: PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance ctor: this=%p\n",this)); michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: sPluginNPPMap[&mNPP] = this; michael@0: #endif michael@0: } michael@0: michael@0: nsNPAPIPluginInstance::~nsNPAPIPluginInstance() michael@0: { michael@0: PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance dtor: this=%p\n",this)); michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: sPluginNPPMap.erase(&mNPP); michael@0: #endif michael@0: michael@0: if (mMIMEType) { michael@0: PR_Free((void *)mMIMEType); michael@0: mMIMEType = nullptr; michael@0: } michael@0: } michael@0: michael@0: uint32_t nsNPAPIPluginInstance::gInUnsafePluginCalls = 0; michael@0: michael@0: void michael@0: nsNPAPIPluginInstance::Destroy() michael@0: { michael@0: Stop(); michael@0: mPlugin = nullptr; michael@0: michael@0: #if MOZ_WIDGET_ANDROID michael@0: if (mContentSurface) michael@0: mContentSurface->SetFrameAvailableCallback(nullptr); michael@0: michael@0: mContentTexture = nullptr; michael@0: mContentSurface = nullptr; michael@0: michael@0: std::map::iterator it; michael@0: for (it = mVideos.begin(); it != mVideos.end(); it++) { michael@0: it->second->mSurfaceTexture->SetFrameAvailableCallback(nullptr); michael@0: delete it->second; michael@0: } michael@0: mVideos.clear(); michael@0: SetWakeLock(false); michael@0: #endif michael@0: } michael@0: michael@0: TimeStamp michael@0: nsNPAPIPluginInstance::StopTime() michael@0: { michael@0: return mStopTime; michael@0: } michael@0: michael@0: nsresult nsNPAPIPluginInstance::Initialize(nsNPAPIPlugin *aPlugin, nsPluginInstanceOwner* aOwner, const char* aMIMEType) michael@0: { michael@0: PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::Initialize this=%p\n",this)); michael@0: michael@0: NS_ENSURE_ARG_POINTER(aPlugin); michael@0: NS_ENSURE_ARG_POINTER(aOwner); michael@0: michael@0: mPlugin = aPlugin; michael@0: mOwner = aOwner; michael@0: michael@0: if (aMIMEType) { michael@0: mMIMEType = (char*)PR_Malloc(strlen(aMIMEType) + 1); michael@0: if (mMIMEType) { michael@0: PL_strcpy(mMIMEType, aMIMEType); michael@0: } michael@0: } michael@0: michael@0: return Start(); michael@0: } michael@0: michael@0: nsresult nsNPAPIPluginInstance::Stop() michael@0: { michael@0: PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::Stop this=%p\n",this)); michael@0: michael@0: // Make sure the plugin didn't leave popups enabled. michael@0: if (mPopupStates.Length() > 0) { michael@0: nsCOMPtr window = GetDOMWindow(); michael@0: michael@0: if (window) { michael@0: window->PopPopupControlState(openAbused); michael@0: } michael@0: } michael@0: michael@0: if (RUNNING != mRunning) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: // clean up all outstanding timers michael@0: for (uint32_t i = mTimers.Length(); i > 0; i--) michael@0: UnscheduleTimer(mTimers[i - 1]->id); michael@0: michael@0: // If there's code from this plugin instance on the stack, delay the michael@0: // destroy. michael@0: if (PluginDestructionGuard::DelayDestroy(this)) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Make sure we lock while we're writing to mRunning after we've michael@0: // started as other threads might be checking that inside a lock. michael@0: { michael@0: AsyncCallbackAutoLock lock; michael@0: mRunning = DESTROYING; michael@0: mStopTime = TimeStamp::Now(); michael@0: } michael@0: michael@0: OnPluginDestroy(&mNPP); michael@0: michael@0: // clean up open streams michael@0: while (mStreamListeners.Length() > 0) { michael@0: nsRefPtr currentListener(mStreamListeners[0]); michael@0: currentListener->CleanUpStream(NPRES_USER_BREAK); michael@0: mStreamListeners.RemoveElement(currentListener); michael@0: } michael@0: michael@0: if (!mPlugin || !mPlugin->GetLibrary()) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs(); michael@0: michael@0: NPError error = NPERR_GENERIC_ERROR; michael@0: if (pluginFunctions->destroy) { michael@0: NPSavedData *sdata = 0; michael@0: michael@0: NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->destroy)(&mNPP, &sdata), this, michael@0: NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO); michael@0: michael@0: NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL, michael@0: ("NPP Destroy called: this=%p, npp=%p, return=%d\n", this, &mNPP, error)); michael@0: } michael@0: mRunning = DESTROYED; michael@0: michael@0: #if MOZ_WIDGET_ANDROID michael@0: for (uint32_t i = 0; i < mPostedEvents.Length(); i++) { michael@0: mPostedEvents[i]->Cancel(); michael@0: } michael@0: michael@0: mPostedEvents.Clear(); michael@0: #endif michael@0: michael@0: nsJSNPRuntime::OnPluginDestroy(&mNPP); michael@0: michael@0: if (error != NPERR_NO_ERROR) michael@0: return NS_ERROR_FAILURE; michael@0: else michael@0: return NS_OK; michael@0: } michael@0: michael@0: already_AddRefed michael@0: nsNPAPIPluginInstance::GetDOMWindow() michael@0: { michael@0: if (!mOwner) michael@0: return nullptr; michael@0: michael@0: nsRefPtr deathGrip(mOwner); michael@0: michael@0: nsCOMPtr doc; michael@0: mOwner->GetDocument(getter_AddRefs(doc)); michael@0: if (!doc) michael@0: return nullptr; michael@0: michael@0: nsRefPtr window = doc->GetWindow(); michael@0: michael@0: return window.forget(); michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::GetTagType(nsPluginTagType *result) michael@0: { michael@0: if (!mOwner) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: return mOwner->GetTagType(result); michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::GetAttributes(uint16_t& n, const char*const*& names, michael@0: const char*const*& values) michael@0: { michael@0: if (!mOwner) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: return mOwner->GetAttributes(n, names, values); michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::GetParameters(uint16_t& n, const char*const*& names, michael@0: const char*const*& values) michael@0: { michael@0: if (!mOwner) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: return mOwner->GetParameters(n, names, values); michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::GetMode(int32_t *result) michael@0: { michael@0: if (mOwner) michael@0: return mOwner->GetMode(result); michael@0: else michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsTArray* michael@0: nsNPAPIPluginInstance::StreamListeners() michael@0: { michael@0: return &mStreamListeners; michael@0: } michael@0: michael@0: nsTArray* michael@0: nsNPAPIPluginInstance::FileCachedStreamListeners() michael@0: { michael@0: return &mFileCachedStreamListeners; michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::Start() michael@0: { michael@0: if (mRunning == RUNNING) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: PluginDestructionGuard guard(this); michael@0: michael@0: uint16_t count = 0; michael@0: const char* const* names = nullptr; michael@0: const char* const* values = nullptr; michael@0: nsPluginTagType tagtype; michael@0: nsresult rv = GetTagType(&tagtype); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: // Note: If we failed to get the tag type, we may be a full page plugin, so no arguments michael@0: rv = GetAttributes(count, names, values); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // nsPluginTagType_Object or Applet may also have PARAM tags michael@0: // Note: The arrays handed back by GetParameters() are michael@0: // crafted specially to be directly behind the arrays from GetAttributes() michael@0: // with a null entry as a separator. This is for 4.x backwards compatibility! michael@0: // see bug 111008 for details michael@0: if (tagtype != nsPluginTagType_Embed) { michael@0: uint16_t pcount = 0; michael@0: const char* const* pnames = nullptr; michael@0: const char* const* pvalues = nullptr; michael@0: if (NS_SUCCEEDED(GetParameters(pcount, pnames, pvalues))) { michael@0: // Android expects an empty string as the separator instead of null michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: NS_ASSERTION(PL_strcmp(values[count], "") == 0, "attribute/parameter array not setup correctly for Android NPAPI plugins"); michael@0: #else michael@0: NS_ASSERTION(!values[count], "attribute/parameter array not setup correctly for NPAPI plugins"); michael@0: #endif michael@0: if (pcount) michael@0: count += ++pcount; // if it's all setup correctly, then all we need is to michael@0: // change the count (attrs + PARAM/blank + params) michael@0: } michael@0: } michael@0: } michael@0: michael@0: int32_t mode; michael@0: const char* mimetype; michael@0: NPError error = NPERR_GENERIC_ERROR; michael@0: michael@0: GetMode(&mode); michael@0: GetMIMEType(&mimetype); michael@0: michael@0: CheckJavaC2PJSObjectQuirk(count, names, values); michael@0: michael@0: // Some older versions of Flash have a bug in them michael@0: // that causes the stack to become currupt if we michael@0: // pass swliveconnect=1 in the NPP_NewProc arrays. michael@0: // See bug 149336 (UNIX), bug 186287 (Mac) michael@0: // michael@0: // The code below disables the attribute unless michael@0: // the environment variable: michael@0: // MOZILLA_PLUGIN_DISABLE_FLASH_SWLIVECONNECT_HACK michael@0: // is set. michael@0: // michael@0: // It is okay to disable this attribute because michael@0: // back in 4.x, scripting required liveconnect to michael@0: // start Java which was slow. Scripting no longer michael@0: // requires starting Java and is quick plus controled michael@0: // from the browser, so Flash now ignores this attribute. michael@0: // michael@0: // This code can not be put at the time of creating michael@0: // the array because we may need to examine the michael@0: // stream header to determine we want Flash. michael@0: michael@0: static const char flashMimeType[] = "application/x-shockwave-flash"; michael@0: static const char blockedParam[] = "swliveconnect"; michael@0: if (count && !PL_strcasecmp(mimetype, flashMimeType)) { michael@0: static int cachedDisableHack = 0; michael@0: if (!cachedDisableHack) { michael@0: if (PR_GetEnv("MOZILLA_PLUGIN_DISABLE_FLASH_SWLIVECONNECT_HACK")) michael@0: cachedDisableHack = -1; michael@0: else michael@0: cachedDisableHack = 1; michael@0: } michael@0: if (cachedDisableHack > 0) { michael@0: for (uint16_t i=0; iGetLibrary(); michael@0: if (!library) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: // Mark this instance as running before calling NPP_New because the plugin may michael@0: // call other NPAPI functions, like NPN_GetURLNotify, that assume this is set michael@0: // before returning. If the plugin returns failure, we'll clear it out below. michael@0: mRunning = RUNNING; michael@0: michael@0: nsresult newResult = library->NPP_New((char*)mimetype, &mNPP, (uint16_t)mode, michael@0: count, (char**)names, (char**)values, michael@0: nullptr, &error); michael@0: mInPluginInitCall = oldVal; michael@0: michael@0: NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL, michael@0: ("NPP New called: this=%p, npp=%p, mime=%s, mode=%d, argc=%d, return=%d\n", michael@0: this, &mNPP, mimetype, mode, count, error)); michael@0: michael@0: if (NS_FAILED(newResult) || error != NPERR_NO_ERROR) { michael@0: mRunning = DESTROYED; michael@0: nsJSNPRuntime::OnPluginDestroy(&mNPP); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult nsNPAPIPluginInstance::SetWindow(NPWindow* window) michael@0: { michael@0: // NPAPI plugins don't want a SetWindow(nullptr). michael@0: if (!window || RUNNING != mRunning) michael@0: return NS_OK; michael@0: michael@0: #if MOZ_WIDGET_GTK michael@0: // bug 108347, flash plugin on linux doesn't like window->width <= michael@0: // 0, but Java needs wants this call. michael@0: if (!nsPluginHost::IsJavaMIMEType(mMIMEType) && window->type == NPWindowTypeWindow && michael@0: (window->width <= 0 || window->height <= 0)) { michael@0: return NS_OK; michael@0: } michael@0: #endif michael@0: michael@0: if (!mPlugin || !mPlugin->GetLibrary()) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs(); michael@0: michael@0: if (pluginFunctions->setwindow) { michael@0: PluginDestructionGuard guard(this); michael@0: michael@0: // XXX Turns out that NPPluginWindow and NPWindow are structurally michael@0: // identical (on purpose!), so there's no need to make a copy. michael@0: michael@0: PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::SetWindow (about to call it) this=%p\n",this)); michael@0: michael@0: bool oldVal = mInPluginInitCall; michael@0: mInPluginInitCall = true; michael@0: michael@0: NPPAutoPusher nppPusher(&mNPP); michael@0: michael@0: DebugOnly error; michael@0: NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->setwindow)(&mNPP, (NPWindow*)window), this, michael@0: NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO); michael@0: michael@0: mInPluginInitCall = oldVal; michael@0: michael@0: NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL, michael@0: ("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", michael@0: this, window->x, window->y, window->width, window->height, michael@0: window->clipRect.top, window->clipRect.bottom, window->clipRect.left, window->clipRect.right, (NPError)error)); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::NewStreamFromPlugin(const char* type, const char* target, michael@0: nsIOutputStream* *result) michael@0: { michael@0: nsPluginStreamToFile* stream = new nsPluginStreamToFile(target, mOwner); michael@0: if (!stream) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: return stream->QueryInterface(kIOutputStreamIID, (void**)result); michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::NewStreamListener(const char* aURL, void* notifyData, michael@0: nsNPAPIPluginStreamListener** listener) michael@0: { michael@0: nsRefPtr sl = new nsNPAPIPluginStreamListener(this, notifyData, aURL); michael@0: michael@0: mStreamListeners.AppendElement(sl); michael@0: michael@0: sl.forget(listener); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult nsNPAPIPluginInstance::Print(NPPrint* platformPrint) michael@0: { michael@0: NS_ENSURE_TRUE(platformPrint, NS_ERROR_NULL_POINTER); michael@0: michael@0: PluginDestructionGuard guard(this); michael@0: michael@0: if (!mPlugin || !mPlugin->GetLibrary()) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs(); michael@0: michael@0: NPPrint* thePrint = (NPPrint *)platformPrint; michael@0: michael@0: // to be compatible with the older SDK versions and to match what michael@0: // NPAPI and other browsers do, overwrite |window.type| field with one michael@0: // more copy of |platformPrint|. See bug 113264 michael@0: uint16_t sdkmajorversion = (pluginFunctions->version & 0xff00)>>8; michael@0: uint16_t sdkminorversion = pluginFunctions->version & 0x00ff; michael@0: if ((sdkmajorversion == 0) && (sdkminorversion < 11)) { michael@0: // Let's copy platformPrint bytes over to where it was supposed to be michael@0: // in older versions -- four bytes towards the beginning of the struct michael@0: // but we should be careful about possible misalignments michael@0: if (sizeof(NPWindowType) >= sizeof(void *)) { michael@0: void* source = thePrint->print.embedPrint.platformPrint; michael@0: void** destination = (void **)&(thePrint->print.embedPrint.window.type); michael@0: *destination = source; michael@0: } else { michael@0: NS_ERROR("Incompatible OS for assignment"); michael@0: } michael@0: } michael@0: michael@0: if (pluginFunctions->print) michael@0: NS_TRY_SAFE_CALL_VOID((*pluginFunctions->print)(&mNPP, thePrint), this, michael@0: NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO); michael@0: michael@0: NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL, michael@0: ("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", michael@0: this, michael@0: platformPrint->print.embedPrint.platformPrint, michael@0: platformPrint->print.embedPrint.window.x, michael@0: platformPrint->print.embedPrint.window.y, michael@0: platformPrint->print.embedPrint.window.width, michael@0: platformPrint->print.embedPrint.window.height, michael@0: platformPrint->print.embedPrint.window.clipRect.top, michael@0: platformPrint->print.embedPrint.window.clipRect.bottom, michael@0: platformPrint->print.embedPrint.window.clipRect.left, michael@0: platformPrint->print.embedPrint.window.clipRect.right)); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult nsNPAPIPluginInstance::HandleEvent(void* event, int16_t* result, michael@0: NSPluginCallReentry aSafeToReenterGecko) michael@0: { michael@0: if (RUNNING != mRunning) michael@0: return NS_OK; michael@0: michael@0: if (!event) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: PluginDestructionGuard guard(this); michael@0: michael@0: if (!mPlugin || !mPlugin->GetLibrary()) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs(); michael@0: michael@0: int16_t tmpResult = kNPEventNotHandled; michael@0: michael@0: if (pluginFunctions->event) { michael@0: mCurrentPluginEvent = event; michael@0: #if defined(XP_WIN) michael@0: NS_TRY_SAFE_CALL_RETURN(tmpResult, (*pluginFunctions->event)(&mNPP, event), this, michael@0: aSafeToReenterGecko); michael@0: #else michael@0: MAIN_THREAD_JNI_REF_GUARD; michael@0: tmpResult = (*pluginFunctions->event)(&mNPP, event); michael@0: #endif michael@0: NPP_PLUGIN_LOG(PLUGIN_LOG_NOISY, michael@0: ("NPP HandleEvent called: this=%p, npp=%p, event=%p, return=%d\n", michael@0: this, &mNPP, event, tmpResult)); michael@0: michael@0: if (result) michael@0: *result = tmpResult; michael@0: mCurrentPluginEvent = nullptr; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult nsNPAPIPluginInstance::GetValueFromPlugin(NPPVariable variable, void* value) michael@0: { michael@0: if (!mPlugin || !mPlugin->GetLibrary()) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs(); michael@0: michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: michael@0: if (pluginFunctions->getvalue && RUNNING == mRunning) { michael@0: PluginDestructionGuard guard(this); michael@0: michael@0: NPError pluginError = NPERR_GENERIC_ERROR; michael@0: NS_TRY_SAFE_CALL_RETURN(pluginError, (*pluginFunctions->getvalue)(&mNPP, variable, value), this, michael@0: NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO); michael@0: NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL, michael@0: ("NPP GetValue called: this=%p, npp=%p, var=%d, value=%d, return=%d\n", michael@0: this, &mNPP, variable, value, pluginError)); michael@0: michael@0: if (pluginError == NPERR_NO_ERROR) { michael@0: rv = NS_OK; michael@0: } michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: nsNPAPIPlugin* nsNPAPIPluginInstance::GetPlugin() michael@0: { michael@0: return mPlugin; michael@0: } michael@0: michael@0: nsresult nsNPAPIPluginInstance::GetNPP(NPP* aNPP) michael@0: { michael@0: if (aNPP) michael@0: *aNPP = &mNPP; michael@0: else michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NPError nsNPAPIPluginInstance::SetWindowless(bool aWindowless) michael@0: { michael@0: mWindowless = aWindowless; michael@0: michael@0: if (mMIMEType) { michael@0: // bug 558434 - Prior to 3.6.4, we assumed windowless was transparent. michael@0: // Silverlight apparently relied on this quirk, so we default to michael@0: // transparent unless they specify otherwise after setting the windowless michael@0: // property. (Last tested version: sl 4.0). michael@0: // Changes to this code should be matched with changes in michael@0: // PluginInstanceChild::InitQuirksMode. michael@0: NS_NAMED_LITERAL_CSTRING(silverlight, "application/x-silverlight"); michael@0: if (!PL_strncasecmp(mMIMEType, silverlight.get(), silverlight.Length())) { michael@0: mTransparent = true; michael@0: } michael@0: } michael@0: michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: NPError nsNPAPIPluginInstance::SetTransparent(bool aTransparent) michael@0: { michael@0: mTransparent = aTransparent; michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: NPError nsNPAPIPluginInstance::SetUsesDOMForCursor(bool aUsesDOMForCursor) michael@0: { michael@0: mUsesDOMForCursor = aUsesDOMForCursor; michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: bool michael@0: nsNPAPIPluginInstance::UsesDOMForCursor() michael@0: { michael@0: return mUsesDOMForCursor; michael@0: } michael@0: michael@0: void nsNPAPIPluginInstance::SetDrawingModel(NPDrawingModel aModel) michael@0: { michael@0: mDrawingModel = aModel; michael@0: } michael@0: michael@0: void nsNPAPIPluginInstance::RedrawPlugin() michael@0: { michael@0: mOwner->RedrawPlugin(); michael@0: } michael@0: michael@0: #if defined(XP_MACOSX) michael@0: void nsNPAPIPluginInstance::SetEventModel(NPEventModel aModel) michael@0: { michael@0: // the event model needs to be set for the object frame immediately michael@0: if (!mOwner) { michael@0: NS_WARNING("Trying to set event model without a plugin instance owner!"); michael@0: return; michael@0: } michael@0: michael@0: mOwner->SetEventModel(aModel); michael@0: } michael@0: #endif michael@0: michael@0: #if defined(MOZ_WIDGET_ANDROID) michael@0: michael@0: static void SendLifecycleEvent(nsNPAPIPluginInstance* aInstance, uint32_t aAction) michael@0: { michael@0: ANPEvent event; michael@0: event.inSize = sizeof(ANPEvent); michael@0: event.eventType = kLifecycle_ANPEventType; michael@0: event.data.lifecycle.action = aAction; michael@0: aInstance->HandleEvent(&event, nullptr); michael@0: } michael@0: michael@0: void nsNPAPIPluginInstance::NotifyForeground(bool aForeground) michael@0: { michael@0: PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::SetForeground this=%p\n foreground=%d",this, aForeground)); michael@0: if (RUNNING != mRunning) michael@0: return; michael@0: michael@0: SendLifecycleEvent(this, aForeground ? kResume_ANPLifecycleAction : kPause_ANPLifecycleAction); michael@0: } michael@0: michael@0: void nsNPAPIPluginInstance::NotifyOnScreen(bool aOnScreen) michael@0: { michael@0: PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::SetOnScreen this=%p\n onScreen=%d",this, aOnScreen)); michael@0: if (RUNNING != mRunning || mOnScreen == aOnScreen) michael@0: return; michael@0: michael@0: mOnScreen = aOnScreen; michael@0: SendLifecycleEvent(this, aOnScreen ? kOnScreen_ANPLifecycleAction : kOffScreen_ANPLifecycleAction); michael@0: } michael@0: michael@0: void nsNPAPIPluginInstance::MemoryPressure() michael@0: { michael@0: PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::MemoryPressure this=%p\n",this)); michael@0: if (RUNNING != mRunning) michael@0: return; michael@0: michael@0: SendLifecycleEvent(this, kFreeMemory_ANPLifecycleAction); michael@0: } michael@0: michael@0: void nsNPAPIPluginInstance::NotifyFullScreen(bool aFullScreen) michael@0: { michael@0: PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::NotifyFullScreen this=%p\n",this)); michael@0: michael@0: if (RUNNING != mRunning || mFullScreen == aFullScreen) michael@0: return; michael@0: michael@0: mFullScreen = aFullScreen; michael@0: SendLifecycleEvent(this, mFullScreen ? kEnterFullScreen_ANPLifecycleAction : kExitFullScreen_ANPLifecycleAction); michael@0: michael@0: if (mFullScreen && mFullScreenOrientation != dom::eScreenOrientation_None) { michael@0: mozilla::widget::android::GeckoAppShell::LockScreenOrientation(mFullScreenOrientation); michael@0: } michael@0: } michael@0: michael@0: void nsNPAPIPluginInstance::NotifySize(nsIntSize size) michael@0: { michael@0: if (kOpenGL_ANPDrawingModel != GetANPDrawingModel() || michael@0: size == mCurrentSize) michael@0: return; michael@0: michael@0: mCurrentSize = size; michael@0: michael@0: ANPEvent event; michael@0: event.inSize = sizeof(ANPEvent); michael@0: event.eventType = kDraw_ANPEventType; michael@0: event.data.draw.model = kOpenGL_ANPDrawingModel; michael@0: event.data.draw.data.surfaceSize.width = size.width; michael@0: event.data.draw.data.surfaceSize.height = size.height; michael@0: michael@0: HandleEvent(&event, nullptr); michael@0: } michael@0: michael@0: void nsNPAPIPluginInstance::SetANPDrawingModel(uint32_t aModel) michael@0: { michael@0: mANPDrawingModel = aModel; michael@0: } michael@0: michael@0: void* nsNPAPIPluginInstance::GetJavaSurface() michael@0: { michael@0: void* surface = nullptr; michael@0: nsresult rv = GetValueFromPlugin(kJavaSurface_ANPGetValue, &surface); michael@0: if (NS_FAILED(rv)) michael@0: return nullptr; michael@0: michael@0: return surface; michael@0: } michael@0: michael@0: void nsNPAPIPluginInstance::PostEvent(void* event) michael@0: { michael@0: PluginEventRunnable *r = new PluginEventRunnable(this, (ANPEvent*)event); michael@0: mPostedEvents.AppendElement(nsRefPtr(r)); michael@0: michael@0: NS_DispatchToMainThread(r); michael@0: } michael@0: michael@0: void nsNPAPIPluginInstance::SetFullScreenOrientation(uint32_t orientation) michael@0: { michael@0: if (mFullScreenOrientation == orientation) michael@0: return; michael@0: michael@0: uint32_t oldOrientation = mFullScreenOrientation; michael@0: mFullScreenOrientation = orientation; michael@0: michael@0: if (mFullScreen) { michael@0: // We're already fullscreen so immediately apply the orientation change michael@0: michael@0: if (mFullScreenOrientation != dom::eScreenOrientation_None) { michael@0: mozilla::widget::android::GeckoAppShell::LockScreenOrientation(mFullScreenOrientation); michael@0: } else if (oldOrientation != dom::eScreenOrientation_None) { michael@0: // We applied an orientation when we entered fullscreen, but michael@0: // we don't want it anymore michael@0: mozilla::widget::android::GeckoAppShell::UnlockScreenOrientation(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: void nsNPAPIPluginInstance::PopPostedEvent(PluginEventRunnable* r) michael@0: { michael@0: mPostedEvents.RemoveElement(r); michael@0: } michael@0: michael@0: void nsNPAPIPluginInstance::SetWakeLock(bool aLocked) michael@0: { michael@0: if (aLocked == mWakeLocked) michael@0: return; michael@0: michael@0: mWakeLocked = aLocked; michael@0: hal::ModifyWakeLock(NS_LITERAL_STRING("nsNPAPIPluginInstance"), michael@0: mWakeLocked ? hal::WAKE_LOCK_ADD_ONE : hal::WAKE_LOCK_REMOVE_ONE, michael@0: hal::WAKE_LOCK_NO_CHANGE); michael@0: } michael@0: michael@0: void nsNPAPIPluginInstance::EnsureSharedTexture() michael@0: { michael@0: if (!mContentTexture) michael@0: mContentTexture = new SharedPluginTexture(); michael@0: } michael@0: michael@0: GLContext* nsNPAPIPluginInstance::GLContext() michael@0: { michael@0: if (!EnsureGLContext()) michael@0: return nullptr; michael@0: michael@0: return sPluginContext; michael@0: } michael@0: michael@0: nsNPAPIPluginInstance::TextureInfo nsNPAPIPluginInstance::LockContentTexture() michael@0: { michael@0: EnsureSharedTexture(); michael@0: return mContentTexture->Lock(); michael@0: } michael@0: michael@0: void nsNPAPIPluginInstance::ReleaseContentTexture(nsNPAPIPluginInstance::TextureInfo& aTextureInfo) michael@0: { michael@0: EnsureSharedTexture(); michael@0: mContentTexture->Release(aTextureInfo); michael@0: } michael@0: michael@0: nsSurfaceTexture* nsNPAPIPluginInstance::CreateSurfaceTexture() michael@0: { michael@0: if (!EnsureGLContext()) michael@0: return nullptr; michael@0: michael@0: GLuint texture = TexturePoolOGL::AcquireTexture(); michael@0: if (!texture) michael@0: return nullptr; michael@0: michael@0: nsSurfaceTexture* surface = nsSurfaceTexture::Create(texture); michael@0: if (!surface) michael@0: return nullptr; michael@0: michael@0: nsCOMPtr frameCallback = NS_NewRunnableMethod(this, &nsNPAPIPluginInstance::OnSurfaceTextureFrameAvailable); michael@0: surface->SetFrameAvailableCallback(frameCallback); michael@0: return surface; michael@0: } michael@0: michael@0: void nsNPAPIPluginInstance::OnSurfaceTextureFrameAvailable() michael@0: { michael@0: if (mRunning == RUNNING && mOwner) michael@0: AndroidBridge::Bridge()->ScheduleComposite(); michael@0: } michael@0: michael@0: void* nsNPAPIPluginInstance::AcquireContentWindow() michael@0: { michael@0: if (!mContentSurface) { michael@0: mContentSurface = CreateSurfaceTexture(); michael@0: michael@0: if (!mContentSurface) michael@0: return nullptr; michael@0: } michael@0: michael@0: return mContentSurface->GetNativeWindow(); michael@0: } michael@0: michael@0: SharedTextureHandle nsNPAPIPluginInstance::CreateSharedHandle() michael@0: { michael@0: if (mContentTexture) { michael@0: return mContentTexture->CreateSharedHandle(); michael@0: } else if (mContentSurface) { michael@0: EnsureGLContext(); michael@0: return gl::CreateSharedHandle(sPluginContext, michael@0: gl::SharedTextureShareType::SameProcess, michael@0: mContentSurface, michael@0: gl::SharedTextureBufferType::SurfaceTexture); michael@0: } else return 0; michael@0: } michael@0: michael@0: void* nsNPAPIPluginInstance::AcquireVideoWindow() michael@0: { michael@0: nsSurfaceTexture* surface = CreateSurfaceTexture(); michael@0: if (!surface) michael@0: return nullptr; michael@0: michael@0: VideoInfo* info = new VideoInfo(surface); michael@0: michael@0: void* window = info->mSurfaceTexture->GetNativeWindow(); michael@0: mVideos.insert(std::pair(window, info)); michael@0: michael@0: return window; michael@0: } michael@0: michael@0: void nsNPAPIPluginInstance::ReleaseVideoWindow(void* window) michael@0: { michael@0: std::map::iterator it = mVideos.find(window); michael@0: if (it == mVideos.end()) michael@0: return; michael@0: michael@0: delete it->second; michael@0: mVideos.erase(window); michael@0: } michael@0: michael@0: void nsNPAPIPluginInstance::SetVideoDimensions(void* window, gfxRect aDimensions) michael@0: { michael@0: std::map::iterator it; michael@0: michael@0: it = mVideos.find(window); michael@0: if (it == mVideos.end()) michael@0: return; michael@0: michael@0: it->second->mDimensions = aDimensions; michael@0: } michael@0: michael@0: void nsNPAPIPluginInstance::GetVideos(nsTArray& aVideos) michael@0: { michael@0: std::map::iterator it; michael@0: for (it = mVideos.begin(); it != mVideos.end(); it++) michael@0: aVideos.AppendElement(it->second); michael@0: } michael@0: michael@0: void nsNPAPIPluginInstance::SetInverted(bool aInverted) michael@0: { michael@0: if (aInverted == mInverted) michael@0: return; michael@0: michael@0: mInverted = aInverted; michael@0: } michael@0: michael@0: nsNPAPIPluginInstance* nsNPAPIPluginInstance::GetFromNPP(NPP npp) michael@0: { michael@0: std::map::iterator it; michael@0: michael@0: it = sPluginNPPMap.find(npp); michael@0: if (it == sPluginNPPMap.end()) michael@0: return nullptr; michael@0: michael@0: return it->second; michael@0: } michael@0: michael@0: #endif michael@0: michael@0: nsresult nsNPAPIPluginInstance::GetDrawingModel(int32_t* aModel) michael@0: { michael@0: #if defined(XP_MACOSX) michael@0: *aModel = (int32_t)mDrawingModel; michael@0: return NS_OK; michael@0: #else michael@0: return NS_ERROR_FAILURE; michael@0: #endif michael@0: } michael@0: michael@0: nsresult nsNPAPIPluginInstance::IsRemoteDrawingCoreAnimation(bool* aDrawing) michael@0: { michael@0: #ifdef XP_MACOSX michael@0: if (!mPlugin) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: PluginLibrary* library = mPlugin->GetLibrary(); michael@0: if (!library) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: return library->IsRemoteDrawingCoreAnimation(&mNPP, aDrawing); michael@0: #else michael@0: return NS_ERROR_FAILURE; michael@0: #endif michael@0: } michael@0: michael@0: nsresult nsNPAPIPluginInstance::ContentsScaleFactorChanged(double aContentsScaleFactor) michael@0: { michael@0: #ifdef XP_MACOSX michael@0: if (!mPlugin) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: PluginLibrary* library = mPlugin->GetLibrary(); michael@0: if (!library) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: // We only need to call this if the plugin is running OOP. michael@0: if (!library->IsOOP()) michael@0: return NS_OK; michael@0: michael@0: return library->ContentsScaleFactorChanged(&mNPP, aContentsScaleFactor); michael@0: #else michael@0: return NS_ERROR_FAILURE; michael@0: #endif michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::GetJSObject(JSContext *cx, JSObject** outObject) michael@0: { michael@0: if (mHaveJavaC2PJSObjectQuirk) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NPObject *npobj = nullptr; michael@0: nsresult rv = GetValueFromPlugin(NPPVpluginScriptableNPObject, &npobj); michael@0: if (NS_FAILED(rv) || !npobj) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: *outObject = nsNPObjWrapper::GetNewOrUsed(&mNPP, cx, npobj); michael@0: michael@0: _releaseobject(npobj); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: nsNPAPIPluginInstance::SetCached(bool aCache) michael@0: { michael@0: mCached = aCache; michael@0: } michael@0: michael@0: bool michael@0: nsNPAPIPluginInstance::ShouldCache() michael@0: { michael@0: return mCached; michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::IsWindowless(bool* isWindowless) michael@0: { michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: // On android, pre-honeycomb, all plugins are treated as windowless. michael@0: *isWindowless = true; michael@0: #else michael@0: *isWindowless = mWindowless; michael@0: #endif michael@0: return NS_OK; michael@0: } michael@0: michael@0: class MOZ_STACK_CLASS AutoPluginLibraryCall michael@0: { michael@0: public: michael@0: AutoPluginLibraryCall(nsNPAPIPluginInstance* aThis) michael@0: : mThis(aThis), mGuard(aThis), mLibrary(nullptr) michael@0: { michael@0: nsNPAPIPlugin* plugin = mThis->GetPlugin(); michael@0: if (plugin) michael@0: mLibrary = plugin->GetLibrary(); michael@0: } michael@0: operator bool() { return !!mLibrary; } michael@0: PluginLibrary* operator->() { return mLibrary; } michael@0: michael@0: private: michael@0: nsNPAPIPluginInstance* mThis; michael@0: PluginDestructionGuard mGuard; michael@0: PluginLibrary* mLibrary; michael@0: }; michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::AsyncSetWindow(NPWindow* window) michael@0: { michael@0: if (RUNNING != mRunning) michael@0: return NS_OK; michael@0: michael@0: AutoPluginLibraryCall library(this); michael@0: if (!library) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: return library->AsyncSetWindow(&mNPP, window); michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::GetImageContainer(ImageContainer**aContainer) michael@0: { michael@0: *aContainer = nullptr; michael@0: michael@0: if (RUNNING != mRunning) michael@0: return NS_OK; michael@0: michael@0: AutoPluginLibraryCall library(this); michael@0: return !library ? NS_ERROR_FAILURE : library->GetImageContainer(&mNPP, aContainer); michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::GetImageSize(nsIntSize* aSize) michael@0: { michael@0: *aSize = nsIntSize(0, 0); michael@0: michael@0: if (RUNNING != mRunning) michael@0: return NS_OK; michael@0: michael@0: AutoPluginLibraryCall library(this); michael@0: return !library ? NS_ERROR_FAILURE : library->GetImageSize(&mNPP, aSize); michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::NotifyPainted(void) michael@0: { michael@0: NS_NOTREACHED("Dead code, shouldn't be called."); michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::GetIsOOP(bool* aIsAsync) michael@0: { michael@0: AutoPluginLibraryCall library(this); michael@0: if (!library) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: *aIsAsync = library->IsOOP(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::SetBackgroundUnknown() michael@0: { michael@0: if (RUNNING != mRunning) michael@0: return NS_OK; michael@0: michael@0: AutoPluginLibraryCall library(this); michael@0: if (!library) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: return library->SetBackgroundUnknown(&mNPP); michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::BeginUpdateBackground(nsIntRect* aRect, michael@0: gfxContext** aContext) michael@0: { michael@0: if (RUNNING != mRunning) michael@0: return NS_OK; michael@0: michael@0: AutoPluginLibraryCall library(this); michael@0: if (!library) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: return library->BeginUpdateBackground(&mNPP, *aRect, aContext); michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::EndUpdateBackground(gfxContext* aContext, michael@0: nsIntRect* aRect) michael@0: { michael@0: if (RUNNING != mRunning) michael@0: return NS_OK; michael@0: michael@0: AutoPluginLibraryCall library(this); michael@0: if (!library) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: return library->EndUpdateBackground(&mNPP, aContext, *aRect); michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::IsTransparent(bool* isTransparent) michael@0: { michael@0: *isTransparent = mTransparent; michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::GetFormValue(nsAString& aValue) michael@0: { michael@0: aValue.Truncate(); michael@0: michael@0: char *value = nullptr; michael@0: nsresult rv = GetValueFromPlugin(NPPVformValue, &value); michael@0: if (NS_FAILED(rv) || !value) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: CopyUTF8toUTF16(value, aValue); michael@0: michael@0: // NPPVformValue allocates with NPN_MemAlloc(), which uses michael@0: // nsMemory. michael@0: nsMemory::Free(value); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::PushPopupsEnabledState(bool aEnabled) michael@0: { michael@0: nsCOMPtr window = GetDOMWindow(); michael@0: if (!window) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: PopupControlState oldState = michael@0: window->PushPopupControlState(aEnabled ? openAllowed : openAbused, michael@0: true); michael@0: michael@0: if (!mPopupStates.AppendElement(oldState)) { michael@0: // Appending to our state stack failed, pop what we just pushed. michael@0: window->PopPopupControlState(oldState); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::PopPopupsEnabledState() michael@0: { michael@0: int32_t last = mPopupStates.Length() - 1; michael@0: michael@0: if (last < 0) { michael@0: // Nothing to pop. michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsCOMPtr window = GetDOMWindow(); michael@0: if (!window) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: PopupControlState &oldState = mPopupStates[last]; michael@0: michael@0: window->PopPopupControlState(oldState); michael@0: michael@0: mPopupStates.RemoveElementAt(last); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::GetPluginAPIVersion(uint16_t* version) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(version); michael@0: michael@0: if (!mPlugin) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: if (!mPlugin->GetLibrary()) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs(); michael@0: michael@0: *version = pluginFunctions->version; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::PrivateModeStateChanged(bool enabled) michael@0: { michael@0: if (RUNNING != mRunning) michael@0: return NS_OK; michael@0: michael@0: PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance informing plugin of private mode state change this=%p\n",this)); michael@0: michael@0: if (!mPlugin || !mPlugin->GetLibrary()) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs(); michael@0: michael@0: if (!pluginFunctions->setvalue) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: PluginDestructionGuard guard(this); michael@0: michael@0: NPError error; michael@0: NPBool value = static_cast(enabled); michael@0: NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->setvalue)(&mNPP, NPNVprivateModeBool, &value), this, michael@0: NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO); michael@0: return (error == NPERR_NO_ERROR) ? NS_OK : NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::IsPrivateBrowsing(bool* aEnabled) michael@0: { michael@0: if (!mOwner) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: nsCOMPtr doc; michael@0: mOwner->GetDocument(getter_AddRefs(doc)); michael@0: NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr domwindow = doc->GetWindow(); michael@0: NS_ENSURE_TRUE(domwindow, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr docShell = domwindow->GetDocShell(); michael@0: nsCOMPtr loadContext = do_QueryInterface(docShell); michael@0: *aEnabled = (loadContext && loadContext->UsePrivateBrowsing()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: static void michael@0: PluginTimerCallback(nsITimer *aTimer, void *aClosure) michael@0: { michael@0: nsNPAPITimer* t = (nsNPAPITimer*)aClosure; michael@0: NPP npp = t->npp; michael@0: uint32_t id = t->id; michael@0: michael@0: PLUGIN_LOG(PLUGIN_LOG_NOISY, ("nsNPAPIPluginInstance running plugin timer callback this=%p\n", npp->ndata)); michael@0: michael@0: MAIN_THREAD_JNI_REF_GUARD; michael@0: // Some plugins (Flash on Android) calls unscheduletimer michael@0: // from this callback. michael@0: t->inCallback = true; michael@0: (*(t->callback))(npp, id); michael@0: t->inCallback = false; michael@0: michael@0: // Make sure we still have an instance and the timer is still alive michael@0: // after the callback. michael@0: nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance*)npp->ndata; michael@0: if (!inst || !inst->TimerWithID(id, nullptr)) michael@0: return; michael@0: michael@0: // use UnscheduleTimer to clean up if this is a one-shot timer michael@0: uint32_t timerType; michael@0: t->timer->GetType(&timerType); michael@0: if (t->needUnschedule || timerType == nsITimer::TYPE_ONE_SHOT) michael@0: inst->UnscheduleTimer(id); michael@0: } michael@0: michael@0: nsNPAPITimer* michael@0: nsNPAPIPluginInstance::TimerWithID(uint32_t id, uint32_t* index) michael@0: { michael@0: uint32_t len = mTimers.Length(); michael@0: for (uint32_t i = 0; i < len; i++) { michael@0: if (mTimers[i]->id == id) { michael@0: if (index) michael@0: *index = i; michael@0: return mTimers[i]; michael@0: } michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: uint32_t michael@0: nsNPAPIPluginInstance::ScheduleTimer(uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID)) michael@0: { michael@0: if (RUNNING != mRunning) michael@0: return 0; michael@0: michael@0: nsNPAPITimer *newTimer = new nsNPAPITimer(); michael@0: michael@0: newTimer->inCallback = newTimer->needUnschedule = false; michael@0: newTimer->npp = &mNPP; michael@0: michael@0: // generate ID that is unique to this instance michael@0: uint32_t uniqueID = mTimers.Length(); michael@0: while ((uniqueID == 0) || TimerWithID(uniqueID, nullptr)) michael@0: uniqueID++; michael@0: newTimer->id = uniqueID; michael@0: michael@0: // create new xpcom timer, scheduled correctly michael@0: nsresult rv; michael@0: nsCOMPtr xpcomTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv); michael@0: if (NS_FAILED(rv)) { michael@0: delete newTimer; michael@0: return 0; michael@0: } michael@0: const short timerType = (repeat ? (short)nsITimer::TYPE_REPEATING_SLACK : (short)nsITimer::TYPE_ONE_SHOT); michael@0: xpcomTimer->InitWithFuncCallback(PluginTimerCallback, newTimer, interval, timerType); michael@0: newTimer->timer = xpcomTimer; michael@0: michael@0: // save callback function michael@0: newTimer->callback = timerFunc; michael@0: michael@0: // add timer to timers array michael@0: mTimers.AppendElement(newTimer); michael@0: michael@0: return newTimer->id; michael@0: } michael@0: michael@0: void michael@0: nsNPAPIPluginInstance::UnscheduleTimer(uint32_t timerID) michael@0: { michael@0: // find the timer struct by ID michael@0: uint32_t index; michael@0: nsNPAPITimer* t = TimerWithID(timerID, &index); michael@0: if (!t) michael@0: return; michael@0: michael@0: if (t->inCallback) { michael@0: t->needUnschedule = true; michael@0: return; michael@0: } michael@0: michael@0: // cancel the timer michael@0: t->timer->Cancel(); michael@0: michael@0: // remove timer struct from array michael@0: mTimers.RemoveElementAt(index); michael@0: michael@0: // delete timer michael@0: delete t; michael@0: } michael@0: michael@0: // Show the context menu at the location for the current event. michael@0: // This can only be called from within an NPP_SendEvent call. michael@0: NPError michael@0: nsNPAPIPluginInstance::PopUpContextMenu(NPMenu* menu) michael@0: { michael@0: if (mOwner && mCurrentPluginEvent) michael@0: return mOwner->ShowNativeContextMenu(menu, mCurrentPluginEvent); michael@0: michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: NPBool michael@0: nsNPAPIPluginInstance::ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, michael@0: double *destX, double *destY, NPCoordinateSpace destSpace) michael@0: { michael@0: if (mOwner) michael@0: return mOwner->ConvertPoint(sourceX, sourceY, sourceSpace, destX, destY, destSpace); michael@0: michael@0: return false; michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::GetDOMElement(nsIDOMElement* *result) michael@0: { michael@0: if (!mOwner) { michael@0: *result = nullptr; michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: return mOwner->GetDOMElement(result); michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::InvalidateRect(NPRect *invalidRect) michael@0: { michael@0: if (RUNNING != mRunning) michael@0: return NS_OK; michael@0: michael@0: if (!mOwner) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: return mOwner->InvalidateRect(invalidRect); michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::InvalidateRegion(NPRegion invalidRegion) michael@0: { michael@0: if (RUNNING != mRunning) michael@0: return NS_OK; michael@0: michael@0: if (!mOwner) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: return mOwner->InvalidateRegion(invalidRegion); michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::GetMIMEType(const char* *result) michael@0: { michael@0: if (!mMIMEType) michael@0: *result = ""; michael@0: else michael@0: *result = mMIMEType; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::GetJSContext(JSContext* *outContext) michael@0: { michael@0: if (!mOwner) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: nsRefPtr deathGrip(mOwner); michael@0: michael@0: *outContext = nullptr; michael@0: nsCOMPtr document; michael@0: michael@0: nsresult rv = mOwner->GetDocument(getter_AddRefs(document)); michael@0: michael@0: if (NS_SUCCEEDED(rv) && document) { michael@0: nsCOMPtr global = michael@0: do_QueryInterface(document->GetWindow()); michael@0: michael@0: if (global) { michael@0: nsIScriptContext *context = global->GetContext(); michael@0: michael@0: if (context) { michael@0: *outContext = context->GetNativeContext(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: nsPluginInstanceOwner* michael@0: nsNPAPIPluginInstance::GetOwner() michael@0: { michael@0: return mOwner; michael@0: } michael@0: michael@0: void michael@0: nsNPAPIPluginInstance::SetOwner(nsPluginInstanceOwner *aOwner) michael@0: { michael@0: mOwner = aOwner; michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::ShowStatus(const char* message) michael@0: { michael@0: if (mOwner) michael@0: return mOwner->ShowStatus(message); michael@0: michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsresult michael@0: nsNPAPIPluginInstance::AsyncSetWindow(NPWindow& window) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: void michael@0: nsNPAPIPluginInstance::URLRedirectResponse(void* notifyData, NPBool allow) michael@0: { michael@0: if (!notifyData) { michael@0: return; michael@0: } michael@0: michael@0: uint32_t listenerCount = mStreamListeners.Length(); michael@0: for (uint32_t i = 0; i < listenerCount; i++) { michael@0: nsNPAPIPluginStreamListener* currentListener = mStreamListeners[i]; michael@0: if (currentListener->GetNotifyData() == notifyData) { michael@0: currentListener->URLRedirectResponse(allow); michael@0: } michael@0: } michael@0: } michael@0: michael@0: NPError michael@0: nsNPAPIPluginInstance::InitAsyncSurface(NPSize *size, NPImageFormat format, michael@0: void *initData, NPAsyncSurface *surface) michael@0: { michael@0: if (mOwner) michael@0: return mOwner->InitAsyncSurface(size, format, initData, surface); michael@0: michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: NPError michael@0: nsNPAPIPluginInstance::FinalizeAsyncSurface(NPAsyncSurface *surface) michael@0: { michael@0: if (mOwner) michael@0: return mOwner->FinalizeAsyncSurface(surface); michael@0: michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: void michael@0: nsNPAPIPluginInstance::SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed) michael@0: { michael@0: if (mOwner) michael@0: mOwner->SetCurrentAsyncSurface(surface, changed); michael@0: } michael@0: michael@0: class CarbonEventModelFailureEvent : public nsRunnable { michael@0: public: michael@0: nsCOMPtr mContent; michael@0: michael@0: CarbonEventModelFailureEvent(nsIContent* aContent) michael@0: : mContent(aContent) michael@0: {} michael@0: michael@0: ~CarbonEventModelFailureEvent() {} michael@0: michael@0: NS_IMETHOD Run(); michael@0: }; michael@0: michael@0: NS_IMETHODIMP michael@0: CarbonEventModelFailureEvent::Run() michael@0: { michael@0: nsString type = NS_LITERAL_STRING("npapi-carbon-event-model-failure"); michael@0: nsContentUtils::DispatchTrustedEvent(mContent->GetDocument(), mContent, michael@0: type, true, true); michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: nsNPAPIPluginInstance::CarbonNPAPIFailure() michael@0: { michael@0: nsCOMPtr element; michael@0: GetDOMElement(getter_AddRefs(element)); michael@0: if (!element) { michael@0: return; michael@0: } michael@0: michael@0: nsCOMPtr content(do_QueryInterface(element)); michael@0: if (!content) { michael@0: return; michael@0: } michael@0: michael@0: nsCOMPtr e = new CarbonEventModelFailureEvent(content); michael@0: nsresult rv = NS_DispatchToCurrentThread(e); michael@0: if (NS_FAILED(rv)) { michael@0: NS_WARNING("Failed to dispatch CarbonEventModelFailureEvent."); michael@0: } michael@0: } michael@0: michael@0: static bool michael@0: GetJavaVersionFromMimetype(nsPluginTag* pluginTag, nsCString& version) michael@0: { michael@0: for (uint32_t i = 0; i < pluginTag->mMimeTypes.Length(); ++i) { michael@0: nsCString type = pluginTag->mMimeTypes[i]; michael@0: nsAutoCString jpi("application/x-java-applet;jpi-version="); michael@0: michael@0: int32_t idx = type.Find(jpi, false, 0, -1); michael@0: if (idx != 0) { michael@0: continue; michael@0: } michael@0: michael@0: type.Cut(0, jpi.Length()); michael@0: if (type.IsEmpty()) { michael@0: continue; michael@0: } michael@0: michael@0: type.ReplaceChar('_', '.'); michael@0: version = type; michael@0: return true; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: void michael@0: nsNPAPIPluginInstance::CheckJavaC2PJSObjectQuirk(uint16_t paramCount, michael@0: const char* const* paramNames, michael@0: const char* const* paramValues) michael@0: { michael@0: if (!mMIMEType || !mPlugin) { michael@0: return; michael@0: } michael@0: michael@0: nsPluginTagType tagtype; michael@0: nsresult rv = GetTagType(&tagtype); michael@0: if (NS_FAILED(rv) || michael@0: (tagtype != nsPluginTagType_Applet)) { michael@0: return; michael@0: } michael@0: michael@0: nsRefPtr pluginHost = nsPluginHost::GetInst(); michael@0: if (!pluginHost) { michael@0: return; michael@0: } michael@0: michael@0: nsPluginTag* pluginTag = pluginHost->TagForPlugin(mPlugin); michael@0: if (!pluginTag || michael@0: !pluginTag->mIsJavaPlugin) { michael@0: return; michael@0: } michael@0: michael@0: // check the params for "code" being present and non-empty michael@0: bool haveCodeParam = false; michael@0: bool isCodeParamEmpty = true; michael@0: michael@0: for (uint16_t i = paramCount; i > 0; --i) { michael@0: if (PL_strcasecmp(paramNames[i - 1], "code") == 0) { michael@0: haveCodeParam = true; michael@0: if (strlen(paramValues[i - 1]) > 0) { michael@0: isCodeParamEmpty = false; michael@0: } michael@0: break; michael@0: } michael@0: } michael@0: michael@0: // Due to the Java version being specified inconsistently across platforms michael@0: // check the version via the mimetype for choosing specific Java versions michael@0: nsCString javaVersion; michael@0: if (!GetJavaVersionFromMimetype(pluginTag, javaVersion)) { michael@0: return; michael@0: } michael@0: michael@0: mozilla::Version version = javaVersion.get(); michael@0: michael@0: if (version >= "1.7.0.4") { michael@0: return; michael@0: } michael@0: michael@0: if (!haveCodeParam && version >= "1.6.0.34" && version < "1.7") { michael@0: return; michael@0: } michael@0: michael@0: if (haveCodeParam && !isCodeParamEmpty) { michael@0: return; michael@0: } michael@0: michael@0: mHaveJavaC2PJSObjectQuirk = true; michael@0: } michael@0: michael@0: double michael@0: nsNPAPIPluginInstance::GetContentsScaleFactor() michael@0: { michael@0: double scaleFactor = 1.0; michael@0: if (mOwner) { michael@0: mOwner->GetContentsScaleFactor(&scaleFactor); michael@0: } michael@0: return scaleFactor; michael@0: }