Bug 730318 - Implement a way for chrome js to enumerate the plugin objects on a page for activation. r=khuey

This commit is contained in:
Jared Wein 2012-03-28 08:53:56 -07:00
Родитель fa552074df
Коммит 5fc2025a5d
13 изменённых файлов: 229 добавлений и 6 удалений

Просмотреть файл

@ -111,6 +111,7 @@ class imgIRequest;
class nsISHEntry; class nsISHEntry;
class nsDOMNavigationTiming; class nsDOMNavigationTiming;
class nsWindowSizes; class nsWindowSizes;
class nsIObjectLoadingContent;
namespace mozilla { namespace mozilla {
namespace css { namespace css {
@ -1570,6 +1571,10 @@ public:
// state is unlocked/false. // state is unlocked/false.
virtual nsresult SetImageLockingState(bool aLocked) = 0; virtual nsresult SetImageLockingState(bool aLocked) = 0;
virtual nsresult AddPlugin(nsIObjectLoadingContent* aPlugin) = 0;
virtual void RemovePlugin(nsIObjectLoadingContent* aPlugin) = 0;
virtual void GetPlugins(nsTArray<nsIObjectLoadingContent*>& aPlugins) = 0;
virtual nsresult GetStateObject(nsIVariant** aResult) = 0; virtual nsresult GetStateObject(nsIVariant** aResult) = 0;
virtual nsDOMNavigationTiming* GetNavigationTiming() const = 0; virtual nsDOMNavigationTiming* GetNavigationTiming() const = 0;

Просмотреть файл

@ -52,7 +52,7 @@ interface nsIURI;
/** /**
* This interface represents a content node that loads objects. * This interface represents a content node that loads objects.
*/ */
[scriptable, uuid(3FF07AB3-5BAC-4D98-9549-5BD15CCEBCD3)] [scriptable, uuid(fd56fda8-d3c3-4368-8cf3-67dbc992aec9)]
interface nsIObjectLoadingContent : nsISupports interface nsIObjectLoadingContent : nsISupports
{ {
const unsigned long TYPE_LOADING = 0; const unsigned long TYPE_LOADING = 0;
@ -125,6 +125,12 @@ interface nsIObjectLoadingContent : nsISupports
*/ */
void playPlugin(); void playPlugin();
/**
* This attribute will return true if the plugin has been activated
* and false if the plugin is still in the click-to-play state.
*/
readonly attribute boolean activated;
[noscript] void stopPluginInstance(); [noscript] void stopPluginInstance();
[noscript] void syncStartPluginInstance(); [noscript] void syncStartPluginInstance();

Просмотреть файл

@ -1674,6 +1674,8 @@ nsDocument::~nsDocument()
// unlocked state, and then clear the table. // unlocked state, and then clear the table.
SetImageLockingState(false); SetImageLockingState(false);
mImageTracker.Clear(); mImageTracker.Clear();
mPlugins.Clear();
} }
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocument) NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocument)
@ -2024,7 +2026,8 @@ nsDocument::Init()
mScriptLoader = new nsScriptLoader(this); mScriptLoader = new nsScriptLoader(this);
NS_ENSURE_TRUE(mScriptLoader, NS_ERROR_OUT_OF_MEMORY); NS_ENSURE_TRUE(mScriptLoader, NS_ERROR_OUT_OF_MEMORY);
if (!mImageTracker.Init()) { if (!mImageTracker.Init() ||
!mPlugins.Init()) {
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
} }
@ -8362,6 +8365,51 @@ nsDocument::RemoveImage(imgIRequest* aImage)
return rv; return rv;
} }
nsresult
nsDocument::AddPlugin(nsIObjectLoadingContent* aPlugin)
{
MOZ_ASSERT(aPlugin);
if (!mPlugins.PutEntry(aPlugin)) {
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
void
nsDocument::RemovePlugin(nsIObjectLoadingContent* aPlugin)
{
MOZ_ASSERT(aPlugin);
mPlugins.RemoveEntry(aPlugin);
}
static bool
AllSubDocumentPluginEnum(nsIDocument* aDocument, void* userArg)
{
nsTArray<nsIObjectLoadingContent*>* plugins =
reinterpret_cast< nsTArray<nsIObjectLoadingContent*>* >(userArg);
MOZ_ASSERT(plugins);
aDocument->GetPlugins(*plugins);
return true;
}
static PLDHashOperator
AllPluginEnum(nsPtrHashKey<nsIObjectLoadingContent>* aPlugin, void* userArg)
{
nsTArray<nsIObjectLoadingContent*>* allPlugins =
reinterpret_cast< nsTArray<nsIObjectLoadingContent*>* >(userArg);
MOZ_ASSERT(allPlugins);
allPlugins->AppendElement(aPlugin->GetKey());
return PL_DHASH_NEXT;
}
void
nsDocument::GetPlugins(nsTArray<nsIObjectLoadingContent*>& aPlugins)
{
aPlugins.SetCapacity(aPlugins.Length() + mPlugins.Count());
mPlugins.EnumerateEntries(AllPluginEnum, &aPlugins);
EnumerateSubDocuments(AllSubDocumentPluginEnum, &aPlugins);
}
PLDHashOperator LockEnumerator(imgIRequest* aKey, PLDHashOperator LockEnumerator(imgIRequest* aKey,
PRUint32 aData, PRUint32 aData,
void* userArg) void* userArg)

Просмотреть файл

@ -935,6 +935,16 @@ public:
virtual NS_HIDDEN_(nsresult) RemoveImage(imgIRequest* aImage); virtual NS_HIDDEN_(nsresult) RemoveImage(imgIRequest* aImage);
virtual NS_HIDDEN_(nsresult) SetImageLockingState(bool aLocked); virtual NS_HIDDEN_(nsresult) SetImageLockingState(bool aLocked);
// AddPlugin adds a plugin-related element to mPlugins when the element is
// added to the tree.
virtual nsresult AddPlugin(nsIObjectLoadingContent* aPlugin);
// RemovePlugin removes a plugin-related element to mPlugins when the
// element is removed from the tree.
virtual void RemovePlugin(nsIObjectLoadingContent* aPlugin);
// GetPlugins returns the plugin-related elements from
// the frame and any subframes.
virtual void GetPlugins(nsTArray<nsIObjectLoadingContent*>& aPlugins);
virtual nsresult GetStateObject(nsIVariant** aResult); virtual nsresult GetStateObject(nsIVariant** aResult);
virtual nsDOMNavigationTiming* GetNavigationTiming() const; virtual nsDOMNavigationTiming* GetNavigationTiming() const;
@ -1304,6 +1314,9 @@ private:
// Tracking for images in the document. // Tracking for images in the document.
nsDataHashtable< nsPtrHashKey<imgIRequest>, PRUint32> mImageTracker; nsDataHashtable< nsPtrHashKey<imgIRequest>, PRUint32> mImageTracker;
// Tracking for plugins in the document.
nsTHashtable< nsPtrHashKey<nsIObjectLoadingContent> > mPlugins;
VisibilityState mVisibilityState; VisibilityState mVisibilityState;
#ifdef DEBUG #ifdef DEBUG

Просмотреть файл

@ -115,6 +115,18 @@ static PRLogModuleInfo* gObjectLog = PR_NewLogModule("objlc");
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
static bool gClickToPlayPlugins = false;
static void
InitPrefCache()
{
static bool initializedPrefCache = false;
if (!initializedPrefCache) {
mozilla::Preferences::AddBoolVarCache(&gClickToPlayPlugins, "plugins.click_to_play");
}
initializedPrefCache = true;
}
class nsAsyncInstantiateEvent : public nsRunnable { class nsAsyncInstantiateEvent : public nsRunnable {
public: public:
nsObjectLoadingContent *mContent; nsObjectLoadingContent *mContent;
@ -556,6 +568,26 @@ bool nsObjectLoadingContent::IsPluginEnabledByExtension(nsIURI* uri, nsCString&
return false; return false;
} }
nsresult
nsObjectLoadingContent::BindToTree(nsIDocument* aDocument, nsIContent* /*aParent*/,
nsIContent* /*aBindingParent*/,
bool /*aCompileEventHandlers*/)
{
if (aDocument) {
return aDocument->AddPlugin(this);
}
return NS_OK;
}
void
nsObjectLoadingContent::UnbindFromTree(bool /*aDeep*/, bool /*aNullParent*/)
{
nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIObjectLoadingContent*>(this));
MOZ_ASSERT(thisContent);
nsIDocument* ownerDoc = thisContent->OwnerDoc();
ownerDoc->RemovePlugin(this);
}
nsObjectLoadingContent::nsObjectLoadingContent() nsObjectLoadingContent::nsObjectLoadingContent()
: mPendingInstantiateEvent(nsnull) : mPendingInstantiateEvent(nsnull)
, mChannel(nsnull) , mChannel(nsnull)
@ -564,11 +596,14 @@ nsObjectLoadingContent::nsObjectLoadingContent()
, mUserDisabled(false) , mUserDisabled(false)
, mSuppressed(false) , mSuppressed(false)
, mNetworkCreated(true) , mNetworkCreated(true)
// If plugins.click_to_play is false, plugins should always play
, mShouldPlay(!mozilla::Preferences::GetBool("plugins.click_to_play", false))
, mSrcStreamLoading(false) , mSrcStreamLoading(false)
, mFallbackReason(ePluginOtherState) , mFallbackReason(ePluginOtherState)
{ {
InitPrefCache();
// If plugins.click_to_play is false, plugins should always play
mShouldPlay = !gClickToPlayPlugins;
// If plugins.click_to_play is true, track the activated state of plugins.
mActivated = !gClickToPlayPlugins;
} }
nsObjectLoadingContent::~nsObjectLoadingContent() nsObjectLoadingContent::~nsObjectLoadingContent()
@ -2216,5 +2251,13 @@ nsObjectLoadingContent::PlayPlugin()
return NS_OK; return NS_OK;
mShouldPlay = true; mShouldPlay = true;
mActivated = true;
return LoadObject(mURI, true, mContentType, true); return LoadObject(mURI, true, mContentType, true);
} }
NS_IMETHODIMP
nsObjectLoadingContent::GetActivated(bool* aActivated)
{
*aActivated = mActivated;
return NS_OK;
}

Просмотреть файл

@ -244,6 +244,12 @@ class nsObjectLoadingContent : public nsImageLoadingContent
static void DoStopPlugin(nsPluginInstanceOwner *aInstanceOwner, bool aDelayedStop); static void DoStopPlugin(nsPluginInstanceOwner *aInstanceOwner, bool aDelayedStop);
nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
bool aCompileEventHandler);
void UnbindFromTree(bool aDeep = true,
bool aNullParent = true);
private: private:
void NotifyContentObjectWrapper(); void NotifyContentObjectWrapper();
@ -399,6 +405,10 @@ class nsObjectLoadingContent : public nsImageLoadingContent
// This is used for click-to-play plugins. // This is used for click-to-play plugins.
bool mShouldPlay : 1; bool mShouldPlay : 1;
// Used to keep track of whether or not a plugin has been played.
// This is used for click-to-play plugins.
bool mActivated : 1;
// Used to track when we might try to instantiate a plugin instance based on // 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 // 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 // want plugin instance instantiation code to attempt to load src data again or

Просмотреть файл

@ -265,6 +265,11 @@ nsHTMLObjectElement::BindToTree(nsIDocument *aDocument,
aCompileEventHandlers); aCompileEventHandlers);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
rv = nsObjectLoadingContent::BindToTree(aDocument, aParent,
aBindingParent,
aCompileEventHandlers);
NS_ENSURE_SUCCESS(rv, rv);
// If we already have all the children, start the load. // If we already have all the children, start the load.
if (mIsDoneAddingChildren) { if (mIsDoneAddingChildren) {
void (nsHTMLObjectElement::*start)() = &nsHTMLObjectElement::StartObjectLoad; void (nsHTMLObjectElement::*start)() = &nsHTMLObjectElement::StartObjectLoad;
@ -279,6 +284,7 @@ nsHTMLObjectElement::UnbindFromTree(bool aDeep,
bool aNullParent) bool aNullParent)
{ {
RemovedFromDocument(); RemovedFromDocument();
nsObjectLoadingContent::UnbindFromTree(aDeep, aNullParent);
nsGenericHTMLFormElement::UnbindFromTree(aDeep, aNullParent); nsGenericHTMLFormElement::UnbindFromTree(aDeep, aNullParent);
} }

Просмотреть файл

@ -283,6 +283,11 @@ nsHTMLSharedObjectElement::BindToTree(nsIDocument *aDocument,
aCompileEventHandlers); aCompileEventHandlers);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
rv = nsObjectLoadingContent::BindToTree(aDocument, aParent,
aBindingParent,
aCompileEventHandlers);
NS_ENSURE_SUCCESS(rv, rv);
// If we already have all the children, start the load. // If we already have all the children, start the load.
if (mIsDoneAddingChildren) { if (mIsDoneAddingChildren) {
void (nsHTMLSharedObjectElement::*start)() = void (nsHTMLSharedObjectElement::*start)() =
@ -298,6 +303,7 @@ nsHTMLSharedObjectElement::UnbindFromTree(bool aDeep,
bool aNullParent) bool aNullParent)
{ {
RemovedFromDocument(); RemovedFromDocument();
nsObjectLoadingContent::UnbindFromTree(aDeep, aNullParent);
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent); nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
} }

Просмотреть файл

@ -51,6 +51,7 @@
#include "nsRefreshDriver.h" #include "nsRefreshDriver.h"
#include "nsDOMTouchEvent.h" #include "nsDOMTouchEvent.h"
#include "nsIDOMTouchEvent.h" #include "nsIDOMTouchEvent.h"
#include "nsObjectLoadingContent.h"
#include "nsIScrollableFrame.h" #include "nsIScrollableFrame.h"
@ -76,6 +77,7 @@
#include "nsCSSProps.h" #include "nsCSSProps.h"
#include "nsDOMFile.h" #include "nsDOMFile.h"
#include "BasicLayers.h" #include "BasicLayers.h"
#include "nsTArrayHelpers.h"
#if defined(MOZ_X11) && defined(MOZ_WIDGET_GTK2) #if defined(MOZ_X11) && defined(MOZ_WIDGET_GTK2)
#include <gdk/gdk.h> #include <gdk/gdk.h>
@ -2230,3 +2232,26 @@ nsDOMWindowUtils::GetPaintingSuppressed(bool *aPaintingSuppressed)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsDOMWindowUtils::GetPlugins(JSContext* cx, jsval* aPlugins)
{
if (!IsUniversalXPConnectCapable()) {
return NS_ERROR_DOM_SECURITY_ERR;
}
nsIDOMDocument* ddoc = mWindow->GetExtantDocument();
nsresult rv;
nsCOMPtr<nsIDocument> doc = do_QueryInterface(ddoc, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsTArray<nsIObjectLoadingContent*> plugins;
doc->GetPlugins(plugins);
JSObject* jsPlugins = nsnull;
rv = nsTArrayToJSArray(cx, plugins, &jsPlugins);
NS_ENSURE_SUCCESS(rv, rv);
*aPlugins = OBJECT_TO_JSVAL(jsPlugins);
return NS_OK;
}

Просмотреть файл

@ -70,7 +70,7 @@ interface nsIDOMFile;
interface nsIFile; interface nsIFile;
interface nsIDOMTouch; interface nsIDOMTouch;
[scriptable, uuid(43feb172-30e1-4ff1-b021-004f973da516)] [scriptable, uuid(c7f303a1-4f7b-4d38-a192-c3f0e25dadb1)]
interface nsIDOMWindowUtils : nsISupports { interface nsIDOMWindowUtils : nsISupports {
/** /**
@ -1099,4 +1099,15 @@ interface nsIDOMWindowUtils : nsISupports {
* otherwise. * otherwise.
*/ */
readonly attribute boolean paintingSuppressed; readonly attribute boolean paintingSuppressed;
/**
* Returns an array of plugins on the page for opt-in activation.
*
* Cannot be accessed from unprivileged context (not content-accessible).
* Will throw a DOM security error if called without UniversalXPConnect
* privileges.
*
*/
[implicit_jscontext]
readonly attribute jsval plugins;
}; };

Просмотреть файл

@ -4090,7 +4090,7 @@ JS_SetElement(JSContext *cx, JSObject *obj, uint32_t index, jsval *vp)
{ {
AssertNoGC(cx); AssertNoGC(cx);
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
assertSameCompartment(cx, obj); assertSameCompartment(cx, obj, *vp);
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING); JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
return obj->setElement(cx, index, vp, false); return obj->setElement(cx, index, vp, false);
} }

Просмотреть файл

@ -49,6 +49,7 @@ EXPORTS = \
nsAXPCNativeCallContext.h \ nsAXPCNativeCallContext.h \
xpc_map_end.h \ xpc_map_end.h \
nsAutoJSValHolder.h \ nsAutoJSValHolder.h \
nsTArrayHelpers.h \
$(NULL) $(NULL)
include $(topsrcdir)/config/rules.mk include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -0,0 +1,49 @@
/* 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/. */
#ifndef __NSTARRAYHELPERS_H__
#define __NSTARRAYHELPERS_H__
template <class T>
inline nsresult
nsTArrayToJSArray(JSContext* aCx, const nsTArray<T>& aSourceArray,
JSObject** aResultArray)
{
MOZ_ASSERT(aCx);
JSAutoRequest ar(aCx);
JSObject* arrayObj = JS_NewArrayObject(aCx, aSourceArray.Length(), nsnull);
if (!arrayObj) {
NS_WARNING("JS_NewArrayObject failed!");
return NS_ERROR_OUT_OF_MEMORY;
}
JSObject* global = JS_GetGlobalForScopeChain(aCx);
MOZ_ASSERT(global);
for (PRUint32 index = 0; index < aSourceArray.Length(); index++) {
nsCOMPtr<nsISupports> obj;
nsresult rv = CallQueryInterface(aSourceArray[index], getter_AddRefs(obj));
NS_ENSURE_SUCCESS(rv, rv);
jsval wrappedVal;
rv = nsContentUtils::WrapNative(aCx, global, obj, &wrappedVal, nsnull, true);
NS_ENSURE_SUCCESS(rv, rv);
if (!JS_SetElement(aCx, arrayObj, index, &wrappedVal)) {
NS_WARNING("JS_SetElement failed!");
return NS_ERROR_FAILURE;
}
}
if (!JS_FreezeObject(aCx, arrayObj)) {
NS_WARNING("JS_FreezeObject failed!");
return NS_ERROR_FAILURE;
}
*aResultArray = arrayObj;
return NS_OK;
}
#endif /* __NSTARRAYHELPERS_H__ */