Bug 998863: Asynchronous Plugin Initialization, Part 2: dom/plugins/base changes; r=johns,josh

This commit is contained in:
Aaron Klotz 2014-12-29 16:12:40 -07:00
parent 7705475b25
commit f0b2e92d9e
10 changed files with 147 additions and 37 deletions

View File

@ -523,7 +523,7 @@ nsNPAPIPluginInstance::Start()
return NS_ERROR_FAILURE;
}
return NS_OK;
return newResult;
}
nsresult nsNPAPIPluginInstance::SetWindow(NPWindow* window)

View File

@ -331,20 +331,32 @@ nsNPAPIPluginStreamListener::OnStartBinding(nsPluginStreamListenerPeer* streamPe
if (error != NPERR_NO_ERROR)
return NS_ERROR_FAILURE;
switch(streamType)
if (streamType == nsPluginStreamListenerPeer::STREAM_TYPE_UNKNOWN) {
SuspendRequest();
} else if (!SetStreamType(streamType, false)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
bool
nsNPAPIPluginStreamListener::SetStreamType(uint16_t aType, bool aNeedsResume)
{
switch(aType)
{
case NP_NORMAL:
mStreamType = NP_NORMAL;
mStreamType = NP_NORMAL;
break;
case NP_ASFILEONLY:
mStreamType = NP_ASFILEONLY;
mStreamType = NP_ASFILEONLY;
break;
case NP_ASFILE:
mStreamType = NP_ASFILE;
mStreamType = NP_ASFILE;
break;
case NP_SEEK:
mStreamType = NP_SEEK;
mStreamType = NP_SEEK;
// Seekable streams should continue to exist even after OnStopRequest
// is fired, so we AddRef ourself an extra time and Release when the
// plugin calls NPN_DestroyStream (CleanUpStream). If the plugin never
@ -353,11 +365,16 @@ nsNPAPIPluginStreamListener::OnStartBinding(nsPluginStreamListenerPeer* streamPe
NS_ADDREF_THIS();
break;
default:
return NS_ERROR_FAILURE;
return false;
}
mStreamStarted = true;
return NS_OK;
if (aNeedsResume) {
if (mStreamListenerPeer) {
mStreamListenerPeer->OnStreamTypeSet(mStreamType);
}
ResumeRequest();
}
return true;
}
void
@ -369,18 +386,20 @@ nsNPAPIPluginStreamListener::SuspendRequest()
nsresult rv = StartDataPump();
if (NS_FAILED(rv))
return;
mIsSuspended = true;
if (mStreamListenerPeer) {
mStreamListenerPeer->SuspendRequests();
mStreamListenerPeer->SuspendRequests();
}
}
void
nsNPAPIPluginStreamListener::ResumeRequest()
{
mStreamListenerPeer->ResumeRequests();
if (mStreamListenerPeer) {
mStreamListenerPeer->ResumeRequests();
}
mIsSuspended = false;
}
@ -390,7 +409,7 @@ nsNPAPIPluginStreamListener::StartDataPump()
nsresult rv;
mDataPumpTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
// Start pumping data to the plugin every 100ms until it obeys and
// eats the data.
return mDataPumpTimer->InitWithCallback(this, 100,

View File

@ -83,6 +83,7 @@ public:
nsresult OnStopBinding(nsPluginStreamListenerPeer* streamPeer,
nsresult status);
nsresult GetStreamType(int32_t *result);
bool SetStreamType(uint16_t aType, bool aNeedsResume = true);
bool IsStarted();
nsresult CleanUpStream(NPReason reason);

View File

@ -50,6 +50,7 @@
#include "nsPluginStreamListenerPeer.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/LoadInfo.h"
#include "mozilla/plugins/PluginAsyncSurrogate.h"
#include "mozilla/plugins/PluginBridge.h"
#include "mozilla/plugins/PluginTypes.h"
#include "mozilla/Preferences.h"
@ -110,6 +111,7 @@
using namespace mozilla;
using mozilla::TimeStamp;
using mozilla::plugins::PluginTag;
using mozilla::plugins::PluginAsyncSurrogate;
// Null out a strong ref to a linked list iteratively to avoid
// exhausting the stack (bug 486349).
@ -830,6 +832,7 @@ nsPluginHost::InstantiatePluginInstance(const char *aMimeType, nsIURI* aURL,
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
const bool isAsyncInit = (rv == NS_PLUGIN_INIT_PENDING);
nsRefPtr<nsNPAPIPluginInstance> instance;
rv = instanceOwner->GetInstance(getter_AddRefs(instance));
@ -837,11 +840,9 @@ nsPluginHost::InstantiatePluginInstance(const char *aMimeType, nsIURI* aURL,
return rv;
}
if (instance) {
instanceOwner->CreateWidget();
// If we've got a native window, the let the plugin know about it.
instanceOwner->CallSetWindow();
// Async init plugins will initiate their own widget creation.
if (!isAsyncInit && instance) {
CreateWidget(instanceOwner);
}
// At this point we consider instantiation to be successful. Do not return an error.
@ -3327,6 +3328,14 @@ nsresult nsPluginHost::NewPluginStreamListener(nsIURI* aURI,
return NS_OK;
}
void nsPluginHost::CreateWidget(nsPluginInstanceOwner* aOwner)
{
aOwner->CreateWidget();
// If we've got a native window, the let the plugin know about it.
aOwner->CallSetWindow();
}
NS_IMETHODIMP nsPluginHost::Observe(nsISupports *aSubject,
const char *aTopic,
const char16_t *someData)
@ -3954,6 +3963,12 @@ PluginDestructionGuard::PluginDestructionGuard(nsNPAPIPluginInstance *aInstance)
Init();
}
PluginDestructionGuard::PluginDestructionGuard(PluginAsyncSurrogate *aSurrogate)
: mInstance(static_cast<nsNPAPIPluginInstance*>(aSurrogate->GetNPP()->ndata))
{
InitAsync();
}
PluginDestructionGuard::PluginDestructionGuard(NPP npp)
: mInstance(npp ? static_cast<nsNPAPIPluginInstance*>(npp->ndata) : nullptr)
{

View File

@ -30,6 +30,12 @@
#include "nsCRT.h"
#include "mozilla/plugins/PluginTypes.h"
namespace mozilla {
namespace plugins {
class PluginAsyncSurrogate;
} // namespace mozilla
} // namespace plugins
class nsNPAPIPlugin;
class nsIComponentManager;
class nsIFile;
@ -203,6 +209,8 @@ public:
nsNPAPIPluginInstance* aInstance,
nsIStreamListener **aStreamListener);
void CreateWidget(nsPluginInstanceOwner* aOwner);
private:
friend class nsPluginUnloadRunnable;
@ -333,11 +341,11 @@ private:
static nsPluginHost* sInst;
};
class MOZ_STACK_CLASS PluginDestructionGuard : protected PRCList
class PluginDestructionGuard : protected PRCList
{
public:
explicit PluginDestructionGuard(nsNPAPIPluginInstance *aInstance);
explicit PluginDestructionGuard(mozilla::plugins::PluginAsyncSurrogate *aSurrogate);
explicit PluginDestructionGuard(NPP npp);
~PluginDestructionGuard();
@ -355,6 +363,18 @@ protected:
PR_INSERT_BEFORE(this, &sListHead);
}
void InitAsync()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread");
mDelayedDestroy = false;
PR_INIT_CLIST(this);
// Instances with active surrogates must be inserted *after* sListHead so
// that they appear to be at the bottom of the stack
PR_INSERT_AFTER(this, &sListHead);
}
nsRefPtr<nsNPAPIPluginInstance> mInstance;
bool mDelayedDestroy;

View File

@ -1452,6 +1452,28 @@ void nsPluginInstanceOwner::ExitFullScreen(jobject view) {
#endif
void
nsPluginInstanceOwner::NotifyHostAsyncInitFailed()
{
nsCOMPtr<nsIObjectLoadingContent> content = do_QueryInterface(mContent);
content->StopPluginInstance();
}
void
nsPluginInstanceOwner::NotifyHostCreateWidget()
{
mPluginHost->CreateWidget(this);
#ifdef XP_MACOSX
FixUpPluginWindow(ePluginPaintEnable);
#else
if (mPluginFrame) {
mPluginFrame->InvalidateFrame();
} else {
CallSetWindow();
}
#endif
}
nsresult nsPluginInstanceOwner::DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent)
{
#ifdef MOZ_WIDGET_ANDROID
@ -3169,6 +3191,10 @@ nsPluginInstanceOwner::UpdateDocumentActiveState(bool aIsActive)
NS_IMETHODIMP
nsPluginInstanceOwner::CallSetWindow()
{
if (!mWidgetCreationComplete) {
// No widget yet, we can't run this code
return NS_OK;
}
if (mPluginFrame) {
mPluginFrame->CallSetWindow(false);
} else if (mInstance) {

View File

@ -255,7 +255,10 @@ public:
// Called from AndroidJNI when we removed the fullscreen view.
static void ExitFullScreen(jobject view);
#endif
void NotifyHostAsyncInitFailed();
void NotifyHostCreateWidget();
private:
virtual ~nsPluginInstanceOwner();

View File

@ -266,6 +266,7 @@ nsPluginStreamListenerPeer::nsPluginStreamListenerPeer()
mHaveFiredOnStartRequest = false;
mDataForwardToRequest = nullptr;
mUseLocalCache = false;
mSeekable = false;
mModified = 0;
mStreamOffset = 0;
@ -533,7 +534,9 @@ nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request,
// Set up the stream listener...
rv = SetUpStreamListener(request, aURL);
if (NS_FAILED(rv)) return rv;
if (NS_FAILED(rv)) {
return rv;
}
return rv;
}
@ -1046,8 +1049,6 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
mPStreamListener->SetStreamListenerPeer(this);
bool useLocalCache = false;
// get httpChannel to retrieve some info we need for nsIPluginStreamInfo setup
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
@ -1103,7 +1104,7 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
nsAutoCString contentEncoding;
if (NS_SUCCEEDED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Encoding"),
contentEncoding))) {
useLocalCache = true;
mUseLocalCache = true;
} else {
// set seekability (seekable if the stream has a known length and if the
// http server accepts byte ranges).
@ -1132,6 +1133,9 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
}
}
MOZ_ASSERT(!mRequest);
mRequest = request;
rv = mPStreamListener->OnStartBinding(this);
mStartBinding = true;
@ -1139,23 +1143,37 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
if (NS_FAILED(rv))
return rv;
mPStreamListener->GetStreamType(&mStreamType);
int32_t streamType = NP_NORMAL;
mPStreamListener->GetStreamType(&streamType);
if (!useLocalCache && mStreamType >= NP_ASFILE) {
// check it out if this is not a file channel.
nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(request);
if (!fileChannel) {
useLocalCache = true;
}
}
if (useLocalCache) {
SetupPluginCacheFile(channel);
if (streamType != STREAM_TYPE_UNKNOWN) {
OnStreamTypeSet(streamType);
}
return NS_OK;
}
void
nsPluginStreamListenerPeer::OnStreamTypeSet(const int32_t aStreamType)
{
MOZ_ASSERT(mRequest);
mStreamType = aStreamType;
if (!mUseLocalCache && mStreamType >= NP_ASFILE) {
// check it out if this is not a file channel.
nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(mRequest);
if (!fileChannel) {
mUseLocalCache = true;
}
}
if (mUseLocalCache) {
nsCOMPtr<nsIChannel> channel = do_QueryInterface(mRequest);
SetupPluginCacheFile(channel);
}
}
const int32_t nsPluginStreamListenerPeer::STREAM_TYPE_UNKNOWN = UINT16_MAX;
nsresult
nsPluginStreamListenerPeer::OnFileAvailable(nsIFile* aFile)
{

View File

@ -128,6 +128,11 @@ public:
requestsCopy[i]->Resume();
}
// Called by nsNPAPIPluginStreamListener
void OnStreamTypeSet(const int32_t aStreamType);
static const int32_t STREAM_TYPE_UNKNOWN;
private:
nsresult SetUpStreamListener(nsIRequest* request, nsIURI* aURL);
nsresult SetupPluginCacheFile(nsIChannel* channel);
@ -159,6 +164,8 @@ private:
nsDataHashtable<nsUint32HashKey, uint32_t>* mDataForwardToRequest;
nsCString mContentType;
bool mUseLocalCache;
nsCOMPtr<nsIRequest> mRequest;
bool mSeekable;
uint32_t mModified;
nsRefPtr<nsNPAPIPluginInstance> mPluginInstance;

View File

@ -330,6 +330,7 @@
ERROR(NS_ERROR_PLUGIN_BLOCKLISTED, FAILURE(1002)),
ERROR(NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED, FAILURE(1003)),
ERROR(NS_ERROR_PLUGIN_CLICKTOPLAY, FAILURE(1004)),
ERROR(NS_PLUGIN_INIT_PENDING, SUCCESS(1005)),
#undef MODULE