forked from mirrors/gecko-dev
There are no code changes, only #include changes. It was a fairly mechanical process: Search for all "AUTO_PROFILER_LABEL", and in each file, if only labels are used, convert "GeckoProfiler.h" into "ProfilerLabels.h" (or just add that last one where needed). In some files, there were also some marker calls but no other profiler-related calls, in these cases "GeckoProfiler.h" was replaced with both "ProfilerLabels.h" and "ProfilerMarkers.h", which still helps in reducing the use of the all-encompassing "GeckoProfiler.h". Differential Revision: https://phabricator.services.mozilla.com/D104588
1189 lines
34 KiB
C++
1189 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 "mozilla/dom/Document.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"
|
|
#include "mozilla/ProfilerLabels.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) {
|
|
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) {
|
|
PopupBlocker::PopPopupControlState(PopupBlocker::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<Document> 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(u"PARAM"_ns);
|
|
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
|
|
|
|
void nsNPAPIPluginInstance::DidComposite() {
|
|
if (RUNNING != mRunning) return;
|
|
|
|
AutoPluginLibraryCall library(this);
|
|
library->DidComposite(&mNPP);
|
|
}
|
|
|
|
nsresult nsNPAPIPluginInstance::NotifyPainted(void) {
|
|
MOZ_ASSERT_UNREACHABLE("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(MakeStringSpan(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;
|
|
|
|
PopupBlocker::PopupControlState oldState =
|
|
PopupBlocker::PushPopupControlState(
|
|
aEnabled ? PopupBlocker::openAllowed : PopupBlocker::openAbused,
|
|
true);
|
|
|
|
// XXX(Bug 1631371) Check if this should use a fallible operation as it
|
|
// pretended earlier.
|
|
mPopupStates.AppendElement(oldState);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult nsNPAPIPluginInstance::PopPopupsEnabledState() {
|
|
if (mPopupStates.IsEmpty()) {
|
|
// Nothing to pop.
|
|
return NS_OK;
|
|
}
|
|
|
|
nsCOMPtr<nsPIDOMWindowOuter> window = GetDOMWindow();
|
|
if (!window) return NS_ERROR_FAILURE;
|
|
|
|
PopupBlocker::PopPopupControlState(mPopupStates.PopLastElement());
|
|
|
|
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<Document> 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;
|
|
}
|
|
|
|
mAudioChannelAgent = new AudioChannelAgent();
|
|
|
|
nsCOMPtr<nsPIDOMWindowOuter> window = GetDOMWindow();
|
|
if (NS_WARN_IF(!window)) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
nsresult 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);
|
|
rv = mAudioChannelAgent->NotifyStartedPlaying(
|
|
mIsMuted ? AudioChannelService::AudibleState::eNotAudible
|
|
: AudioChannelService::AudibleState::eAudible);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return;
|
|
}
|
|
|
|
mAudioChannelAgent->PullInitialUpdate();
|
|
}
|
|
|
|
void nsNPAPIPluginInstance::NotifyStoppedPlaying() {
|
|
MOZ_ASSERT(mAudioChannelAgent);
|
|
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
|
|
if (mWindowMuted != aMuted) {
|
|
mWindowMuted = aMuted;
|
|
return UpdateMutedIfNeeded();
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNPAPIPluginInstance::WindowSuspendChanged(nsSuspendedTypes aSuspend) {
|
|
MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
|
|
("nsNPAPIPluginInstance, WindowSuspendChanged, "
|
|
"this = %p, aSuspend = %s\n",
|
|
this, SuspendTypeToStr(aSuspend)));
|
|
const bool isSuspended = aSuspend != nsISuspendedTypes::NONE_SUSPENDED;
|
|
if (mWindowSuspended != isSuspended) {
|
|
mWindowSuspended = isSuspended;
|
|
// It doesn't support suspending, so we just do something like mute/unmute.
|
|
return UpdateMutedIfNeeded();
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNPAPIPluginInstance::WindowAudioCaptureChanged(bool aCapture) {
|
|
return NS_OK;
|
|
}
|
|
|
|
void nsNPAPIPluginInstance::NotifyAudibleStateChanged() const {
|
|
// This happens when global window destroyed, we would notify agent's callback
|
|
// to mute its volume, but the nsNSNPAPI had released the agent before that.
|
|
if (!mAudioChannelAgent) {
|
|
return;
|
|
}
|
|
AudioChannelService::AudibleState audibleState =
|
|
mIsMuted ? AudioChannelService::AudibleState::eNotAudible
|
|
: AudioChannelService::AudibleState::eAudible;
|
|
// Because we don't really support suspending nsNPAPI, so all audible changes
|
|
// come from changing its volume.
|
|
mAudioChannelAgent->NotifyStartedAudible(
|
|
audibleState, AudioChannelService::AudibleChangedReasons::eVolumeChanged);
|
|
}
|
|
|
|
nsresult nsNPAPIPluginInstance::UpdateMutedIfNeeded() {
|
|
const bool shouldMute = mWindowSuspended || mWindowMuted;
|
|
if (mIsMuted == shouldMute) {
|
|
return NS_OK;
|
|
}
|
|
|
|
mIsMuted = shouldMute;
|
|
NotifyAudibleStateChanged();
|
|
nsresult rv = SetMuted(mIsMuted);
|
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "SetMuted failed");
|
|
return rv;
|
|
}
|
|
|
|
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;
|
|
}
|