Files
palemoon27/dom/plugins/base/nsNPAPIPluginInstance.cpp
T
roytam1 0af135f24d import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1249212 part 3 - Fix active duration calculation when iteration duration is infinity; r=boris (acc98b1948)
- Bug 1249212 part 4 - Add tests for activeDuration; r=boris (354da323ef)
- Bug 1249212 part 5 - Remove max() clamping from endTime calculation; r=boris (613cd6f5b7)
- Bug 1249212 part 6 - Add tests for endTime calculation; r=boris (583a09f942)
- Bug 1249212 part 7 - Calculate the endTime in GetComputedTimingAt; r=boris (ac73c4a853)
- No bug - Fix whitespace and four test descriptions in keyframe-effect tests; r=whitespace-only DONTBUILD (844a12ba4d)
- Bug 1249212 part 1 - Simplify various keyframe-effect tests; r=boris (58c7f5ef19)
- Bug 1241929 - remove PurgeActiveWorker() from install job when skip waiting is set. r=bkelly (248aadb430)
- Bug 1238954 P1 Purge potentially controlled document entries when evicting service worker registrations. r=ehsan (094bb54de1)
- Bug 1238954 P2 Fix csp service worker tests to register and unregister separate scopes. r=ehsan (71f0237c11)
- Bug 1227015 P2 Move mScriptSpec from registration job into script job base. r=ehsan (754753f0f6)
- Bug 1227015 P3 Require a script spec on install jobs. r=ehsan (ebdbf860b9)
- Bug 1227015 P4 Make register job always require an explicit script spec. r=ehsan (b97ec80a56)
- Bug 1227015 P5 Remove ServiceWorkerRegistrationInfo mScriptSpec. r=ehsan (4410fd9fd0)
- Bug 1227015 P6 Abort updates if the script spec has changed. r=ehsan (01962f2915)
- Bug 1232444 Only store service worker registrations after install is successful. r=baku (f773638ec6)
- Bug 1231974 P1 Remove unneeded ServiceWorkerScriptJobBase abstract class. r=baku (c514e53d82)
- Bug 1231974 P2 Store scope on ServiceWorkerJobBase. r=baku (d723846d45)
- Bug 1231974 P3 Store the principal on the ServiceWorkerJobBase. r=baku (550fa7f1d4)
- Bug 1231974 P4 Lazy load registration and verify it does not change in service worker jobs. r=baku (db44008f8f)
- Bug 1231974 P6 Abort update-triggered install jobs if the service worker script has changed. r=baku (3e7572968f)
- Bug 1237992 - service worker activate should be executed after install onstatechange events are fired. r=bkelly (58de5a2e57)
- No bug - Correct the order of two newly added web-platform tests in manifest. DONTBUILD (e14b162237)
- Bug 1189581 - Make service-workers/service-worker/fetch-cors-xhr.https.html pass; r=bkelly (e1dbe77c87)
- Bug 1243942 - Bypass service workers for WebSocket handshake channels; r=bkelly (845fd17110)
- Bug 1217089 - Remove fetch-request-html-imports.https.html; r=bkelly (528ea318b6)
- Bug 1188545 - Update expected results for some service worker tests. a=testonly (ba29add4a5)
- Bug 1213119 Lengthen timeout in test checking for failure to load iframes and windows. r=ehsan (d25f8f9b01)
- Bug 1189671 - Fix getregistrations test. r=jgraham (2407499bc5)
- Bug 1217367 - Add a wpt test that verified coalesced .update() calls resolve properly. r=bkelly (7e3f4a92e1)
- Bug 1200677 - Import navigation-redirect.https.html for non-e10s. r=jdm (6e6d98a255)
- Bug 1251498: Implement IDBKeyRange.includes(). r=baku (89c839adaf)
- Bug 1248338 - Implement iterationStart; r=birtles (5dcb1341c3)
- Bug 1244635 - Part1 Add enddelay implementation in dom/animation/AnimationEffectTiming.cpp r=bz,hiro (e0a9f3a798)
- Bug 1244635 - Part2 Add enddelay tests in dom/animation/test/chrome r=hiro (98d2f5ada5)
- Bug 1244635 - Part3 Add enddelay tests in testing/web-platform/tests/web-animations r=hiro (bb10a41382)
- Bug 1244635 - Part4 Add enddelay tests in layout/style/test r=hiro (ceda978f3e)
- Bug 1237173 - Part1: Move TimingParam struct to a new file. r=birtles (ad46be831b)
- Bug 1251804 - Use the ImageContainer's size and not the intrinsic size when computing the transform in nsDisplayImage::ConfigureLayer. r=tn (23bd3774ff)
- Bug 1247554 - Budget creation of AGRs by frame area; r=mattwoodrow (c68183c77e)
- Require mix-blend mode support in all compositors and layer managers. (bug 1209278 part 1, r=mstange) (e00752064f)
- Remove lazy scrollinfo hoisting introduced in bug 1193557. (bug 1209278 part 2, r=mstange) (394c117b8d)
- Bug 1152049 - Apply all scroll clips when computing plugin clips in content. r=tn (9c44108dda)
- Bug 1238564 - Anticipate async scrolling when computing the scroll clipped bounds of a display list. r=roc (4c28888eb6)
- Bug 1238564 - Allow constructing nsDisplayWrapList with a given scroll clip. r=roc (dd6d6d1a02)
- Fold nsDisplayBlendContainer constructors. (bug 1209278 part 3, r=mstange) (e28cb8d062)
- Bug 1253052. Only schedule paint when apz aware event listener is added if event regions/apz are enabled. r=kats (4a2dcd2e31)
- Bug 1252929: Next.1. Make layers.max-active preference not need a restart. r=mstange (412d52ff81)
- Bug 1247554 - Mark nsPresContext::GetVisibleArea as const; r=mattwoodrow (8ad99e89a2)
- Bug 1104916 - Implement CSS media query display-mode. r=cam (6bf38de62c)
- Bug 1247098 - Mark nsIPresShell::GetResolution and nsPresContext::IsRootContentDocument as const. r=tnikkel (2514fe01c2)
- Bug 1253078 - Switch MOZ_STYLO environmental variable to MOZ_DISABLE_STYLO. r=dholbert (8c6dfe008e)
- Bug 1232181 - Notify plugins about scroll state. r=roc (1eccaad547)
- Bug 1198663. Tolerate null Image in Android NPAPI plugins. r=snorp (bfceeacbe8)
- Bug 1232181 - Add an image layer for plugin frames that represent windowed plugins on platforms that support scroll capture. r=roc (c064e01b19)
- Bug 1171182 - Browser Zoom Query for NPAPI; r=bsmedberg r=jaas (95c60d2190)
- Bug 1243639 - Remove Honeycomb flash-related code. r=snorp (437bdfa5e8)
- Bug 1177367 - Don't fall through to non-e10s plugin widget creation when e10s creation fails. r=aklotz (7fb106e260)
- Bug 1250634 - Part 0: Fix MacroAssembler support for store16(). r=jandem (99fdf6fd42)
- Bug 1250634 - Part 1: Refactor FreeSpan management to be less indirect and confusing. r=terrence, r=jandem (50f57a129c)
- Bug 1253094, part 5 - Stop using DebugOnly for class/struct members in layout/. r=mats (bcb94cc110)
- Bug 1238564 - Set the innermost possible scroll clip on opacity items during creation. r=mattwoodrow (da5072cb75)
- Bug 1192910 - Ensure we flush paints on the main thread during an APZ flush. r=mstange (ff4631bcd8)
- Bug 1254263 - Add a flag to allow disabling paint-skipping. r=mstange (90375f4f31)
- Bug 1248913 - nsDisplayListBuilder doesn't need to know what blend modes it contains, just whether it contains any. r=mattwoodrow (92c987df65)
- Bug 1248913 - Add a constructor argument to nsDisplayMixBlendMode that lets you specify the blend mode. r=mattwoodrow (66234cc69c)
- Bug 1238564 - When building a fixed/sticky display item, don't restore the clip until we're ready to build that item so that inner items aren't unnecessarily clipped. r=roc (752f531f08)
- Bug 1238564 - Include mIsAsyncScrollable information in DisplayItemScrollClip::ToString. r=roc (b6ac4899eb)
- Bug 1238564 - Don't do another pass over the display list to figure out ancestor scroll clips. r=mattwoodrow (12ad134528)
- Bug 1238564 - Get rid of cross stacking context parent scroll clip. r=mattwoodrow (536faa6ba6)
- Bug 1248913 - Rename nsDisplayMixBlendMode to nsDisplayBlendMode. r=mattwoodrow (34a0704841)
- Bug 1248913 - Let nsDisplayBackgroundImage specify the background blend mode. r=mattwoodrow (cc671af9e3)
- Bug 619500: Part 1. Default sizing for specified size of SVG images which have no constraints; r=dholbert r=seth (b0f7ec56a8)
- Bug 619500: Part 2. When drawing an SVG image as a CSS border-image, use preverveAspectRatio="none"; r=dholbert (1dad64f38c)
- Bug 619500: Part 3. svg-as-borderimage test cases; r=dholbert (896d339cf9)
- Bug 619500: Part 4. Remove one unused data member in SVGDrawingParameters; r=dholbert (f16e9a5927)
- Bug 1230415 - Use DrawTarget instead of gfxContext in PaintBorderWithStyleBorder(). r=roc. (f00cccb284)
- Bug 1248913 - Build nsDisplayBlendMode items for background-blend-mode. r=mattwoodrow (105515a553)
- Bug 1248913 - Remove mCanBeActive and second nsDisplayBlendContainer constructor. r=mattwoodrow (d984db61f5)
- Bug 1248913 - Make nsDisplayBlendContainer active or inactive based on its contents. r=mattwoodrow (f44fa4f479)
- Bug 1248913 - Reftest. (58a1507343)
- Bug 1251833 - Part 1: Move allocation into FreeSpan and move firstFreeSpan to the top of Arenas. r=terrence (3f4d239785)
- Bug 1251833 - Part 2: Clean up the various iterators a bit. r=terrence (300aa5673d)
- Bug 1251527 - Don't override visible regions for background-attachment:fixed. r=mstange (ee2d53334d)
- Backout e00a02282951 (bug 1232229) as we no longer need the diagnostics. (22f0063541)
- Bug 1250718 - Don't flatten opacity to an intermediate surface when used in the middle of preserve-3d. r=thinker (9df994b834)
- Bug 1196114 - Part 1: Add SetPerformanceWarning. r=birtles (165f9cbcfc)
- Bug 1196114 - Part 2: Add AnimationPropertyStatus interface and KeyframeEffectReadOnly.runningStatus(). r=birtles,smaug (4e3d2d55e0)
- Bug 1196114 - Part 3: Set AnimationPerformanceWarning messages. r=birtles (cd3497e128)
- Bug 1196114 - Part 4: Localize messages for animation performance warnings. r=birtles (1b1676b7b6)
- Bug 1196114 - Part 5: Store performce warning information as enum type. r=birtles (d2ec6643d3)
- Bug 1221378: Properly root object passed to the allocation metadata callback. r=fitzgen (37831b769c)
- Bug 1225005 - Clamp negative values in containing block size. r=roc (8e525d5265)
- Bug 1192245 - Fix tests that fail with incremental zeal r=terrence (6ca6f63135)
- Bug 1249367 - Make background finalization a GC phase (and clean up Zones properly); r=jonco (43d9a1fafe)
- Bug 1119537 - Make decommit a proper GC phase; r=jonco (638492711e)
- Bug 1232229 - Add assertions to prevent nursery allocation when setting up OMT parse tasks r=terrence (e12cd405c2)
- Backed out changeset 2a613f5a5866 (bug 1119537) for hazard failures (623123a764)
- Bug 1249896 - Part 6: Add gc namespace for Arena::thingsSpan. r=terrence (ba1e1d41b0)
- Bug 1251833 - Part 3: Merge ArenaHeader into Arena. r=terrence (e8bd53b44e)
- Bug 1232181 - Plugin module plumbing for retrieving scroll captures and updating plugin instance content scroll state. r=roc (2309d423cc)
- Bug 1232181 - Add a few win resource helpers. r=aklotz (1421a9695a)
- Bug 1232181 - Add support for capturing plugin windows on Windows. r=aklotz (4ccbfeb19e)
2024-02-06 10:15:07 +08:00

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