mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-27 12:15:33 +00:00
8bbbeee495
MozReview-Commit-ID: 4WihVmQaclk --HG-- extra : rebase_source : 44cdc24585cfd847833bd217ed39c39206f896ed extra : intermediate-source : d1c028cb1f42741d2bfb42435f79ddfb0022ba11 extra : source : 15e8c2a618839f34cc269a105832d5d7763a4b30
1376 lines
34 KiB
C++
1376 lines
34 KiB
C++
/* -*- 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"
|
|
|
|
#include "mozilla/Logging.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 "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/Element.h"
|
|
#include "mozilla/dom/HTMLObjectElementBinding.h"
|
|
#include "AudioChannelService.h"
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::dom;
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::plugins::parent;
|
|
using namespace mozilla::layers;
|
|
|
|
NS_IMPL_ISUPPORTS(nsNPAPIPluginInstance, nsIAudioChannelAgentCallback)
|
|
|
|
nsNPAPIPluginInstance::nsNPAPIPluginInstance()
|
|
: mDrawingModel(kDefaultDrawingModel)
|
|
, 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
|
|
, 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));
|
|
}
|
|
|
|
nsNPAPIPluginInstance::~nsNPAPIPluginInstance()
|
|
{
|
|
PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance dtor: this=%p\n",this));
|
|
|
|
if (mMIMEType) {
|
|
free(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;
|
|
}
|
|
|
|
TimeStamp
|
|
nsNPAPIPluginInstance::StopTime()
|
|
{
|
|
return mStopTime;
|
|
}
|
|
|
|
nsresult nsNPAPIPluginInstance::Initialize(nsNPAPIPlugin *aPlugin, nsPluginInstanceOwner* aOwner, const nsACString& aMIMEType)
|
|
{
|
|
AUTO_PROFILER_LABEL("nsNPAPIPlugin::Initialize", 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;
|
|
}
|
|
|
|
mRunning = DESTROYING;
|
|
mStopTime = TimeStamp::Now();
|
|
|
|
// 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;
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
mCachedParamNames[attributes.Length()] = ToNewUTF8String(NS_LITERAL_STRING("PARAM"));
|
|
mCachedParamValues[attributes.Length()] = nullptr;
|
|
|
|
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++;
|
|
}
|
|
|
|
const char* mimetype;
|
|
NPError error = NPERR_GENERIC_ERROR;
|
|
|
|
GetMIMEType(&mimetype);
|
|
|
|
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,
|
|
quirkParamLength, mCachedParamNames,
|
|
mCachedParamValues, nullptr, &error);
|
|
mInPluginInitCall = oldVal;
|
|
|
|
NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
|
|
("NPP New called: this=%p, npp=%p, mime=%s, argc=%d, return=%d\n",
|
|
this, &mNPP, mimetype, 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
|
|
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::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;
|
|
|
|
AUTO_PROFILER_LABEL("nsNPAPIPluginInstance::HandleEvent", 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
|
|
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=%p, 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;
|
|
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
|
|
|
|
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)
|
|
{
|
|
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(XP_MACOSX)
|
|
// All OS X plugins are 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));
|
|
|
|
// 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;
|
|
const short timerType = (repeat ? (short)nsITimer::TYPE_REPEATING_SLACK : (short)nsITimer::TYPE_ONE_SHOT);
|
|
rv = NS_NewTimerWithFuncCallback(getter_AddRefs(newTimer->timer),
|
|
PluginTimerCallback,
|
|
newTimer,
|
|
interval,
|
|
timerType,
|
|
"nsNPAPIPluginInstance::ScheduleTimer");
|
|
if (NS_FAILED(rv)) {
|
|
delete newTimer;
|
|
return 0;
|
|
}
|
|
|
|
// 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(Element** 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);
|
|
}
|
|
}
|
|
|
|
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::CreateAudioChannelAgentIfNeeded()
|
|
{
|
|
if (mAudioChannelAgent) {
|
|
return NS_OK;
|
|
}
|
|
|
|
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(), this);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsNPAPIPluginInstance::NotifyStartedPlaying()
|
|
{
|
|
nsresult rv = CreateAudioChannelAgentIfNeeded();
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return;
|
|
}
|
|
|
|
MOZ_ASSERT(mAudioChannelAgent);
|
|
dom::AudioPlaybackConfig config;
|
|
rv = mAudioChannelAgent->NotifyStartedPlaying(&config,
|
|
dom::AudioChannelService::AudibleState::eAudible);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return;
|
|
}
|
|
|
|
rv = WindowVolumeChanged(config.mVolume, config.mMuted);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return;
|
|
}
|
|
|
|
// Since we only support muting for now, the implementation of suspend
|
|
// is equal to muting. Therefore, if we have already muted the plugin,
|
|
// then we don't need to call WindowSuspendChanged() again.
|
|
if (config.mMuted) {
|
|
return;
|
|
}
|
|
|
|
rv = WindowSuspendChanged(config.mSuspend);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
void
|
|
nsNPAPIPluginInstance::NotifyStoppedPlaying()
|
|
{
|
|
MOZ_ASSERT(mAudioChannelAgent);
|
|
|
|
// Reset the attribute.
|
|
mMuted = false;
|
|
nsresult rv = mAudioChannelAgent->NotifyStoppedPlaying();
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNPAPIPluginInstance::WindowVolumeChanged(float aVolume, bool aMuted)
|
|
{
|
|
MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
|
|
("nsNPAPIPluginInstance, WindowVolumeChanged, "
|
|
"this = %p, aVolume = %f, aMuted = %s\n",
|
|
this, aVolume, aMuted ? "true" : "false"));
|
|
|
|
// We just support mute/unmute
|
|
nsresult rv = SetMuted(aMuted);
|
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "SetMuted failed");
|
|
if (mMuted != aMuted) {
|
|
mMuted = aMuted;
|
|
if (mAudioChannelAgent) {
|
|
AudioChannelService::AudibleState audible = aMuted ?
|
|
AudioChannelService::AudibleState::eNotAudible :
|
|
AudioChannelService::AudibleState::eAudible;
|
|
mAudioChannelAgent->NotifyStartedAudible(audible,
|
|
AudioChannelService::AudibleChangedReasons::eVolumeChanged);
|
|
}
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNPAPIPluginInstance::WindowSuspendChanged(nsSuspendedTypes aSuspend)
|
|
{
|
|
MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
|
|
("nsNPAPIPluginInstance, WindowSuspendChanged, "
|
|
"this = %p, aSuspend = %s\n", this, SuspendTypeToStr(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;
|
|
}
|