Bug 810082 - Part 0.5 - Add script access event for CTP'd plugins r=joshmoz

This commit is contained in:
John Schoenick 2012-12-07 14:50:10 -08:00
parent 8d249e9c73
commit 6e8178b713
5 changed files with 84 additions and 32 deletions

View File

@ -21,7 +21,7 @@ interface nsIURI;
* This interface represents a content node that loads objects.
*/
[scriptable, uuid(a812424b-4820-4e28-96c8-dd2b69e36496)]
[scriptable, uuid(649b8a75-8623-437f-ad30-0ac596c8452e)]
interface nsIObjectLoadingContent : nsISupports
{
/**
@ -130,6 +130,16 @@ interface nsIObjectLoadingContent : nsISupports
[noscript] void syncStartPluginInstance();
[noscript] void asyncStartPluginInstance();
/**
* Requests the plugin instance for scripting, attempting to spawn it if
* appropriate.
*
* The first time content js tries to access a pre-empted plugin
* (click-to-play or play preview), an event is dispatched.
*/
[noscript] nsNPAPIPluginInstancePtr
scriptRequestPluginInstance(in bool callerIsContentJS);
/**
* The URL of the data/src loaded in the object. This may be null (i.e.
* an <embed> with no src).

View File

@ -163,27 +163,31 @@ InDocCheckEvent::Run()
}
/**
* A task for firing PluginNotFound and PluginBlocklisted DOM Events.
* Helper task for firing simple events
*/
class nsPluginOutdatedEvent : public nsRunnable {
class nsSimplePluginEvent : public nsRunnable {
public:
nsPluginOutdatedEvent(nsIContent* aContent) : mContent(aContent) {}
nsSimplePluginEvent(nsIContent* aContent, const nsAString &aEvent)
: mContent(aContent),
mEvent(aEvent)
{}
~nsPluginOutdatedEvent() {}
~nsSimplePluginEvent() {}
NS_IMETHOD Run();
private:
nsCOMPtr<nsIContent> mContent;
nsString mEvent;
};
NS_IMETHODIMP
nsPluginOutdatedEvent::Run()
nsSimplePluginEvent::Run()
{
LOG(("OBJLC [%p]: nsPluginOutdatedEvent firing", mContent.get()));
LOG(("OBJLC [%p]: nsSimplePluginEvent firing event \"%s\"", mContent.get(),
mEvent.get()));
nsContentUtils::DispatchTrustedEvent(mContent->GetDocument(), mContent,
NS_LITERAL_STRING("PluginOutdated"),
true, true);
mEvent, true, true);
return NS_OK;
}
@ -631,6 +635,7 @@ nsObjectLoadingContent::nsObjectLoadingContent()
, mPlayPreviewCanceled(false)
, mIsStopping(false)
, mIsLoading(false)
, mScriptRequested(false)
, mSrcStreamLoading(false) {}
nsObjectLoadingContent::~nsObjectLoadingContent()
@ -748,12 +753,13 @@ nsObjectLoadingContent::InstantiatePluginInstance()
EmptyString(), &blockState);
if (blockState == nsIBlocklistService::STATE_OUTDATED) {
// Fire plugin outdated event if necessary
LOG(("OBJLC [%p]: Dispatching nsPluginOutdatedEvent for content %p\n",
LOG(("OBJLC [%p]: Dispatching plugin outdated event for content %p\n",
this));
nsCOMPtr<nsIRunnable> ev = new nsPluginOutdatedEvent(thisContent);
nsCOMPtr<nsIRunnable> ev = new nsSimplePluginEvent(thisContent,
NS_LITERAL_STRING("PluginOutdated"));
nsresult rv = NS_DispatchToCurrentThread(ev);
if (NS_FAILED(rv)) {
NS_WARNING("failed to dispatch nsPluginOutdatedEvent");
NS_WARNING("failed to dispatch nsSimplePluginEvent");
}
}
}
@ -2013,6 +2019,8 @@ nsObjectLoadingContent::UnloadObject(bool aResetState)
mOriginalContentType.Truncate();
}
mScriptRequested = false;
// This call should be last as it may re-enter
StopPluginInstance();
}
@ -2183,6 +2191,45 @@ nsObjectLoadingContent::PluginCrashed(nsIPluginTag* aPluginTag,
return NS_OK;
}
NS_IMETHODIMP
nsObjectLoadingContent::ScriptRequestPluginInstance(bool aCallerIsContentJS,
nsNPAPIPluginInstance **aResult)
{
nsCOMPtr<nsIContent> thisContent =
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
*aResult = nullptr;
// The first time content script attempts to access placeholder content, fire
// an event. Fallback types >= eFallbackClickToPlay are plugin-replacement
// types, see header.
if (aCallerIsContentJS && !mScriptRequested &&
InActiveDocument(thisContent) && mType == eType_Null &&
mFallbackType >= eFallbackClickToPlay) {
nsCOMPtr<nsIRunnable> ev =
new nsSimplePluginEvent(thisContent,
NS_LITERAL_STRING("PluginScripted"));
nsresult rv = NS_DispatchToCurrentThread(ev);
if (NS_FAILED(rv)) {
NS_NOTREACHED("failed to dispatch PluginScripted event");
}
mScriptRequested = true;
} else if (mType == eType_Plugin && !mInstanceOwner &&
nsContentUtils::IsSafeToRunScript() &&
InActiveDocument(thisContent)) {
// If we're configured as a plugin in an active document and it's safe to
// run scripts right now, try spawning synchronously
SyncStartPluginInstance();
}
if (mInstanceOwner) {
return mInstanceOwner->GetInstance(aResult);
}
// Note that returning a null plugin is expected (and happens often)
return NS_OK;
}
NS_IMETHODIMP
nsObjectLoadingContent::SyncStartPluginInstance()
{

View File

@ -437,12 +437,16 @@ class nsObjectLoadingContent : public nsImageLoadingContent
// Protects LoadObject from re-entry
bool mIsLoading : 1;
// For plugin stand-in types (click-to-play, play preview, ...) tracks
// whether content js has tried to access the plugin script object.
bool mScriptRequested : 1;
// Used to track when we might try to instantiate a plugin instance based on
// a src data stream being delivered to this object. When this is true we
// don't want plugin instance instantiation code to attempt to load src data
// again or we'll deliver duplicate streams. Should be cleared when we are
// not loading src data.
bool mSrcStreamLoading;
bool mSrcStreamLoading : 1;
nsWeakFrame mPrintFrame;

View File

@ -9563,6 +9563,7 @@ nsHTMLSelectElementSH::SetProperty(nsIXPConnectWrappedNative *wrapper,
nsresult
nsHTMLPluginObjElementSH::GetPluginInstanceIfSafe(nsIXPConnectWrappedNative *wrapper,
JSObject *obj,
JSContext *cx,
nsNPAPIPluginInstance **_result)
{
*_result = nullptr;
@ -9573,22 +9574,11 @@ nsHTMLPluginObjElementSH::GetPluginInstanceIfSafe(nsIXPConnectWrappedNative *wra
nsCOMPtr<nsIObjectLoadingContent> objlc(do_QueryInterface(content));
NS_ASSERTION(objlc, "Object nodes must implement nsIObjectLoadingContent");
nsresult rv = objlc->GetPluginInstance(_result);
if (NS_SUCCEEDED(rv) && *_result) {
return rv;
}
// If it's not safe to run script we'll only return the instance if it exists.
// Ditto if the document is inactive.
if (!nsContentUtils::IsSafeToRunScript() || !content->OwnerDoc()->IsActive()) {
return rv;
}
// We don't care if this actually starts the plugin or not, we just want to
// try to start it now if possible.
objlc->SyncStartPluginInstance();
return objlc->GetPluginInstance(_result);
bool callerIsContentJS = (!xpc::AccessCheck::callerIsChrome() &&
!xpc::AccessCheck::callerIsXBL(cx) &&
js::IsContextRunningJS(cx));
return objlc->ScriptRequestPluginInstance(callerIsContentJS,
_result);
}
class nsPluginProtoChainInstallRunner MOZ_FINAL : public nsIRunnable
@ -9649,7 +9639,7 @@ nsHTMLPluginObjElementSH::SetupProtoChain(nsIXPConnectWrappedNative *wrapper,
JSAutoCompartment ac(cx, obj);
nsRefPtr<nsNPAPIPluginInstance> pi;
nsresult rv = GetPluginInstanceIfSafe(wrapper, obj, getter_AddRefs(pi));
nsresult rv = GetPluginInstanceIfSafe(wrapper, obj, cx, getter_AddRefs(pi));
NS_ENSURE_SUCCESS(rv, rv);
if (!pi) {
@ -9855,7 +9845,7 @@ nsHTMLPluginObjElementSH::Call(nsIXPConnectWrappedNative *wrapper,
jsval *argv, jsval *vp, bool *_retval)
{
nsRefPtr<nsNPAPIPluginInstance> pi;
nsresult rv = GetPluginInstanceIfSafe(wrapper, obj, getter_AddRefs(pi));
nsresult rv = GetPluginInstanceIfSafe(wrapper, obj, cx, getter_AddRefs(pi));
NS_ENSURE_SUCCESS(rv, rv);
// If obj is a native wrapper, or if there's no plugin around for
@ -9922,7 +9912,7 @@ nsHTMLPluginObjElementSH::NewResolve(nsIXPConnectWrappedNative *wrapper,
// possible.
nsRefPtr<nsNPAPIPluginInstance> pi;
nsresult rv = GetPluginInstanceIfSafe(wrapper, obj, getter_AddRefs(pi));
nsresult rv = GetPluginInstanceIfSafe(wrapper, obj, cx, getter_AddRefs(pi));
NS_ENSURE_SUCCESS(rv, rv);
return nsElementSH::NewResolve(wrapper, cx, obj, id, flags, objp,

View File

@ -848,6 +848,7 @@ protected:
static nsresult GetPluginInstanceIfSafe(nsIXPConnectWrappedNative *aWrapper,
JSObject *obj,
JSContext *cx,
nsNPAPIPluginInstance **aResult);
static nsresult GetPluginJSObject(JSContext *cx, JSObject *obj,