Bug 851917. Get rid of the classinfo for HTMLObjectElement, HTMLEmbedElement, HTMLAppletElement, and rip out nsHTMLPluginObjElementSH. r=peterv,johns

This commit is contained in:
Boris Zbarsky 2013-04-10 13:49:05 -04:00
Родитель 8b269e0c3a
Коммит 01d3eba57a
10 изменённых файлов: 251 добавлений и 642 удалений

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

@ -25,7 +25,7 @@ interface nsIURI;
* interface to mirror this interface when changing it.
*/
[scriptable, uuid(e2ef99fe-f7d3-422f-a7b4-834e8bdde710)]
[scriptable, uuid(24a35de3-40e4-498e-9c1b-2fd0a2d4cae5)]
interface nsIObjectLoadingContent : nsISupports
{
/**
@ -149,16 +149,6 @@ interface nsIObjectLoadingContent : nsISupports
*/
[noscript] void initializeFromChannel(in nsIRequest request);
/**
* 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).

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

@ -75,6 +75,7 @@
#include "nsWidgetsCID.h"
#include "nsContentCID.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/Telemetry.h"
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
@ -2345,10 +2346,21 @@ nsObjectLoadingContent::PluginCrashed(nsIPluginTag* aPluginTag,
return NS_OK;
}
NS_IMETHODIMP
nsObjectLoadingContent::ScriptRequestPluginInstance(bool aCallerIsContentJS,
nsresult
nsObjectLoadingContent::ScriptRequestPluginInstance(JSContext* aCx,
nsNPAPIPluginInstance **aResult)
{
// The below methods pull the cx off the stack, so make sure they match.
//
// NB: Sometimes there's a null cx on the stack, in which case |cx| is the
// safe JS context. But in that case, IsCallerChrome() will return true,
// so the ensuing expression is short-circuited.
MOZ_ASSERT_IF(nsContentUtils::GetCurrentJSContext(),
aCx == nsContentUtils::GetCurrentJSContext());
bool callerIsContentJS = (!nsContentUtils::IsCallerChrome() &&
!nsContentUtils::IsCallerXBL() &&
js::IsContextRunningJS(aCx));
nsCOMPtr<nsIContent> thisContent =
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
@ -2357,7 +2369,7 @@ nsObjectLoadingContent::ScriptRequestPluginInstance(bool aCallerIsContentJS,
// 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 &&
if (callerIsContentJS && !mScriptRequested &&
InActiveDocument(thisContent) && mType == eType_Null &&
mFallbackType >= eFallbackClickToPlay) {
nsCOMPtr<nsIRunnable> ev =
@ -2628,27 +2640,7 @@ nsObjectLoadingContent::NotifyContentObjectWrapper()
return;
}
JSAutoCompartment ac(cx, obj);
nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
JSObject* canonicalPrototype = nullptr;
if (thisContent->IsDOMBinding()) {
canonicalPrototype =
GetCanonicalPrototype(cx, JS_GetGlobalForObject(cx, obj));
} else{
nsContentUtils::XPConnect()->
GetWrappedNativeOfNativeObject(cx, sgo->GetGlobalJSObject(), thisContent,
NS_GET_IID(nsISupports),
getter_AddRefs(wrapper));
}
nsHTMLPluginObjElementSH::SetupProtoChain(cx, obj, wrapper, canonicalPrototype);
}
JSObject*
nsObjectLoadingContent::GetCanonicalPrototype(JSContext* aCx, JSObject* aGlobal)
{
return nullptr;
SetupProtoChain(cx, obj);
}
NS_IMETHODIMP
@ -2874,48 +2866,197 @@ nsObjectLoadingContent::LegacyCall(JSContext* aCx,
return JS::UndefinedValue();
}
JS::Value retval;
bool otherRetval;
nsresult rv =
nsHTMLPluginObjElementSH::DoCall(nullptr, aCx, obj, args.Length(),
args.Elements(), &retval, aThisVal,
&otherRetval);
nsRefPtr<nsNPAPIPluginInstance> pi;
nsresult rv = ScriptRequestPluginInstance(aCx, getter_AddRefs(pi));
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return JS::UndefinedValue();
}
if (!otherRetval) {
// if there's no plugin around for this object, throw.
if (!pi) {
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
return JS::UndefinedValue();
}
JSObject *pi_obj;
JSObject *pi_proto;
rv = GetPluginJSObject(aCx, obj, pi, &pi_obj, &pi_proto);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return JS::UndefinedValue();
}
if (!pi_obj) {
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
return JS::UndefinedValue();
}
JS::Value retval;
bool ok = ::JS::Call(aCx, aThisVal, pi_obj, args.Length(),
args.Elements(), &retval);
if (!ok) {
aRv.Throw(NS_ERROR_FAILURE);
return JS::UndefinedValue();
}
Telemetry::Accumulate(Telemetry::PLUGIN_CALLED_DIRECTLY, true);
return retval;
}
void
nsObjectLoadingContent::SetupProtoChain(JSContext* aCx, JSObject* aObject)
{
// We get called on random compartments here for some reason
// (perhaps because WrapObject can happen on a random compartment?)
// so make sure to enter the compartment of aObject.
JSAutoCompartment ac(aCx, aObject);
MOZ_ASSERT(nsCOMPtr<nsIContent>(do_QueryInterface(
static_cast<nsIObjectLoadingContent*>(this)))->IsDOMBinding());
if (nsContentUtils::IsSafeToRunScript()) {
nsHTMLPluginObjElementSH::SetupProtoChain(aCx, aObject, nullptr,
GetCanonicalPrototype(aCx,
JS_GetGlobalForObject(aCx, aObject)));
} else {
if (mType != eType_Plugin) {
return;
}
if (!nsContentUtils::IsSafeToRunScript()) {
// This may be null if the JS context is not a DOM context. That's ok, we'll
// use the safe context from XPConnect in the runnable.
nsCOMPtr<nsIScriptContext> scriptContext = GetScriptContextFromJSContext(aCx);
nsRefPtr<nsHTMLPluginObjElementSH::SetupProtoChainRunner> runner =
new nsHTMLPluginObjElementSH::SetupProtoChainRunner(nullptr,
scriptContext,
this);
nsRefPtr<SetupProtoChainRunner> runner =
new SetupProtoChainRunner(scriptContext, this);
nsContentUtils::AddScriptRunner(runner);
return;
}
// We get called on random compartments here for some reason
// (perhaps because WrapObject can happen on a random compartment?)
// so make sure to enter the compartment of aObject.
MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
JSAutoRequest ar(aCx);
JSAutoCompartment ac(aCx, aObject);
nsRefPtr<nsNPAPIPluginInstance> pi;
nsresult rv = ScriptRequestPluginInstance(aCx, getter_AddRefs(pi));
if (NS_FAILED(rv)) {
return;
}
if (!pi) {
// No plugin around for this object.
return;
}
JSObject *pi_obj; // XPConnect-wrapped peer object, when we get it.
JSObject *pi_proto; // 'pi.__proto__'
rv = GetPluginJSObject(aCx, aObject, pi, &pi_obj, &pi_proto);
if (NS_FAILED(rv)) {
return;
}
if (!pi_obj) {
// Didn't get a plugin instance JSObject, nothing we can do then.
return;
}
// If we got an xpconnect-wrapped plugin object, set obj's
// prototype's prototype to the scriptable plugin.
JSObject *my_proto =
GetDOMClass(aObject)->mGetProto(aCx, JS_GetGlobalForObject(aCx, aObject));
MOZ_ASSERT(my_proto);
// Set 'this.__proto__' to pi
if (!::JS_SetPrototype(aCx, aObject, pi_obj)) {
return;
}
if (pi_proto && js::GetObjectClass(pi_proto) != &js::ObjectClass) {
// The plugin wrapper has a proto that's not Object.prototype, set
// 'pi.__proto__.__proto__' to the original 'this.__proto__'
if (pi_proto != my_proto && !::JS_SetPrototype(aCx, pi_proto, my_proto)) {
return;
}
} else {
// 'pi' didn't have a prototype, or pi's proto was
// 'Object.prototype' (i.e. pi is an NPRuntime wrapped JS object)
// set 'pi.__proto__' to the original 'this.__proto__'
if (!::JS_SetPrototype(aCx, pi_obj, my_proto)) {
return;
}
}
// Before this proto dance the objects involved looked like this:
//
// this.__proto__.__proto__
// ^ ^ ^
// | | |__ Object.prototype
// | |
// | |__ WebIDL prototype (shared)
// |
// |__ WebIDL object
//
// pi.__proto__
// ^ ^
// | |__ Object.prototype or some other object
// |
// |__ Plugin NPRuntime JS object wrapper
//
// Now, after the above prototype setup the prototype chain should
// look like this if pi.__proto__ was Object.prototype:
//
// this.__proto__.__proto__.__proto__
// ^ ^ ^ ^
// | | | |__ Object.prototype
// | | |
// | | |__ WebIDL prototype (shared)
// | |
// | |__ Plugin NPRuntime JS object wrapper
// |
// |__ WebIDL object
//
// or like this if pi.__proto__ was some other object:
//
// this.__proto__.__proto__.__proto__.__proto__
// ^ ^ ^ ^ ^
// | | | | |__ Object.prototype
// | | | |
// | | | |__ WebIDL prototype (shared)
// | | |
// | | |__ old pi.__proto__
// | |
// | |__ Plugin NPRuntime JS object wrapper
// |
// |__ WebIDL object
//
}
// static
nsresult
nsObjectLoadingContent::GetPluginJSObject(JSContext *cx, JSObject *obj,
nsNPAPIPluginInstance *plugin_inst,
JSObject **plugin_obj,
JSObject **plugin_proto)
{
*plugin_obj = nullptr;
*plugin_proto = nullptr;
JSAutoRequest ar(cx);
// NB: We need an AutoEnterCompartment because we can be called from
// nsObjectFrame when the plugin loads after the JS object for our content
// node has been created.
JSAutoCompartment ac(cx, obj);
if (plugin_inst) {
plugin_inst->GetJSObject(cx, plugin_obj);
if (*plugin_obj) {
if (!::JS_GetPrototype(cx, *plugin_obj, plugin_proto)) {
return NS_ERROR_UNEXPECTED;
}
}
}
return NS_OK;
}
void
@ -2970,15 +3111,45 @@ nsObjectLoadingContent::DoNewResolve(JSContext* aCx, JSHandleObject aObject,
{
// We don't resolve anything; we just try to make sure we're instantiated
bool callerIsContentJS = (!nsContentUtils::IsCallerChrome() &&
!nsContentUtils::IsCallerXBL() &&
js::IsContextRunningJS(aCx));
nsRefPtr<nsNPAPIPluginInstance> pi;
nsresult rv = ScriptRequestPluginInstance(callerIsContentJS,
getter_AddRefs(pi));
nsresult rv = ScriptRequestPluginInstance(aCx, getter_AddRefs(pi));
if (NS_FAILED(rv)) {
return mozilla::dom::Throw<true>(aCx, rv);
}
return true;
}
// SetupProtoChainRunner implementation
nsObjectLoadingContent::SetupProtoChainRunner::SetupProtoChainRunner(
nsIScriptContext* scriptContext,
nsObjectLoadingContent* aContent)
: mContext(scriptContext)
, mContent(aContent)
{
}
NS_IMETHODIMP
nsObjectLoadingContent::SetupProtoChainRunner::Run()
{
// XXXbz Does it really matter what JSContext we use here? Seems
// like we could just always use the safe context....
nsCxPusher pusher;
JSContext* cx = mContext ? mContext->GetNativeContext()
: nsContentUtils::GetSafeJSContext();
pusher.Push(cx);
nsCOMPtr<nsIContent> content;
CallQueryInterface(mContent.get(), getter_AddRefs(content));
JSObject* obj = content->GetWrapper();
if (!obj) {
// No need to set up our proto chain if we don't even have an object
return NS_OK;
}
nsObjectLoadingContent* objectLoadingContent =
static_cast<nsObjectLoadingContent*>(mContent.get());
objectLoadingContent->SetupProtoChain(cx, obj);
return NS_OK;
}
NS_IMPL_ISUPPORTS1(nsObjectLoadingContent::SetupProtoChainRunner, nsIRunnable)

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

@ -136,8 +136,6 @@ class nsObjectLoadingContent : public nsImageLoadingContent
* object by placing it on the prototype chain of our element,
* between the element itself and its most-derived DOM prototype.
*
* GetCanonicalPrototype returns this most-derived DOM prototype.
*
* SetupProtoChain handles actually inserting the plug-in
* scriptable object into the proto chain if needed.
*
@ -145,13 +143,6 @@ class nsObjectLoadingContent : public nsImageLoadingContent
* page is looking up a property name on our object and make sure
* that our plug-in, if any, is instantiated.
*/
/**
* Get the canonical prototype for this content for the given global. Only
* returns non-null for objects that are on WebIDL bindings.
*/
virtual JSObject* GetCanonicalPrototype(JSContext* aCx, JSObject* aGlobal);
// Helper for WebIDL node wrapping
void SetupProtoChain(JSContext* aCx, JSObject* aObject);
@ -443,6 +434,34 @@ class nsObjectLoadingContent : public nsImageLoadingContent
*/
nsObjectFrame* GetExistingFrame();
// Helper class for SetupProtoChain
class SetupProtoChainRunner MOZ_FINAL : public nsIRunnable
{
public:
NS_DECL_ISUPPORTS
SetupProtoChainRunner(nsIScriptContext* scriptContext,
nsObjectLoadingContent* aContent);
NS_IMETHOD Run();
private:
nsCOMPtr<nsIScriptContext> mContext;
// We store an nsIObjectLoadingContent because we can
// unambiguously refcount that.
nsRefPtr<nsIObjectLoadingContent> mContent;
};
// Utility getter for getting our nsNPAPIPluginInstance in a safe way.
nsresult ScriptRequestPluginInstance(JSContext* aCx,
nsNPAPIPluginInstance** aResult);
// Utility method for getting our plugin JSObject
static nsresult GetPluginJSObject(JSContext *cx, JSObject *obj,
nsNPAPIPluginInstance *plugin_inst,
JSObject **plugin_obj,
JSObject **plugin_proto);
// The final listener for mChannel (uriloader, pluginstreamlistener, etc.)
nsCOMPtr<nsIStreamListener> mFinalListener;

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

@ -96,7 +96,7 @@ NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLObjectElement)
NS_OFFSET_AND_INTERFACE_TABLE_END
NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(HTMLObjectElement,
nsGenericHTMLFormElement)
NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLObjectElement)
NS_HTML_CONTENT_INTERFACE_MAP_END
NS_IMPL_ELEMENT_CLONE(HTMLObjectElement)
@ -463,15 +463,7 @@ HTMLObjectElement::WrapNode(JSContext* aCx, JSObject* aScope)
return obj;
}
JSObject*
HTMLObjectElement::GetCanonicalPrototype(JSContext* aCx, JSObject* aGlobal)
{
return HTMLObjectElementBinding::GetProtoObject(aCx, aGlobal);
}
} // namespace dom
} // namespace mozilla
DOMCI_NODE_DATA(HTMLObjectElement, mozilla::dom::HTMLObjectElement)
NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Object)

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

@ -96,8 +96,6 @@ public:
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLObjectElement,
nsGenericHTMLFormElement)
virtual nsXPCClassInfo* GetClassInfo();
virtual nsIDOMNode* AsDOMNode() { return this; }
// Web IDL binding methods
@ -246,8 +244,6 @@ private:
virtual void SetItemValueText(const nsAString& text);
virtual JSObject* WrapNode(JSContext *aCx, JSObject *aScope) MOZ_OVERRIDE;
virtual JSObject* GetCanonicalPrototype(JSContext* aCx,
JSObject* aGlobal) MOZ_OVERRIDE;
bool mIsDoneAddingChildren;
};

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

@ -20,9 +20,6 @@
NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(SharedObject)
DOMCI_DATA(HTMLAppletElement, mozilla::dom::HTMLSharedObjectElement)
DOMCI_DATA(HTMLEmbedElement, mozilla::dom::HTMLSharedObjectElement)
namespace mozilla {
namespace dom {
@ -94,18 +91,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_ADDREF_INHERITED(HTMLSharedObjectElement, Element)
NS_IMPL_RELEASE_INHERITED(HTMLSharedObjectElement, Element)
nsIClassInfo*
HTMLSharedObjectElement::GetClassInfoInternal()
{
if (mNodeInfo->Equals(nsGkAtoms::applet)) {
return NS_GetDOMClassInfoInstance(eDOMClassInfo_HTMLAppletElement_id);
}
if (mNodeInfo->Equals(nsGkAtoms::embed)) {
return NS_GetDOMClassInfoInstance(eDOMClassInfo_HTMLEmbedElement_id);
}
return nullptr;
}
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLSharedObjectElement)
NS_HTML_CONTENT_INTERFACE_TABLE_AMBIGUOUS_BEGIN(HTMLSharedObjectElement,
nsIDOMHTMLAppletElement)
@ -125,7 +110,6 @@ NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLSharedObjectElement)
NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLAppletElement, applet)
NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLEmbedElement, embed)
NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMGetSVGDocument, embed)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_GETTER(GetClassInfoInternal)
NS_HTML_CONTENT_INTERFACE_MAP_END
NS_IMPL_ELEMENT_CLONE(HTMLSharedObjectElement)
@ -382,15 +366,5 @@ HTMLSharedObjectElement::WrapNode(JSContext* aCx, JSObject* aScope)
return obj;
}
JSObject*
HTMLSharedObjectElement::GetCanonicalPrototype(JSContext* aCx, JSObject* aGlobal)
{
if (mNodeInfo->Equals(nsGkAtoms::applet)) {
return HTMLAppletElementBinding::GetProtoObject(aCx, aGlobal);
}
MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::embed));
return HTMLEmbedElementBinding::GetProtoObject(aCx, aGlobal);
}
} // namespace dom
} // namespace mozilla

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

@ -94,12 +94,6 @@ public:
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(HTMLSharedObjectElement,
nsGenericHTMLElement)
virtual nsXPCClassInfo* GetClassInfo()
{
return static_cast<nsXPCClassInfo*>(GetClassInfoInternal());
}
nsIClassInfo* GetClassInfoInternal();
virtual nsIDOMNode* AsDOMNode()
{
return static_cast<nsIDOMHTMLAppletElement*>(this);
@ -246,8 +240,6 @@ private:
virtual void SetItemValueText(const nsAString& text);
virtual JSObject* WrapNode(JSContext *aCx, JSObject *aScope) MOZ_OVERRIDE;
virtual JSObject* GetCanonicalPrototype(JSContext* aCx,
JSObject* aGlobal) MOZ_OVERRIDE;
};
} // namespace dom

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

@ -119,12 +119,6 @@
// HTMLSelectElement helper includes
#include "nsIDOMHTMLSelectElement.h"
// HTMLEmbed/ObjectElement helper includes
#include "nsNPAPIPluginInstance.h"
#include "nsIObjectFrame.h"
#include "nsObjectLoadingContent.h"
#include "nsIPluginHost.h"
#include "nsIDOMHTMLOptionElement.h"
// Event related includes
@ -192,12 +186,9 @@
#include "nsIDOMElementCSSInlineStyle.h"
#include "nsIDOMLinkStyle.h"
#include "nsIDOMHTMLDocument.h"
#include "nsIDOMHTMLAppletElement.h"
#include "nsIDOMHTMLCanvasElement.h"
#include "nsIDOMHTMLEmbedElement.h"
#include "nsIDOMHTMLIFrameElement.h"
#include "nsIDOMHTMLInputElement.h"
#include "nsIDOMHTMLObjectElement.h"
#include "nsIDOMCSSCharsetRule.h"
#include "nsIDOMCSSImportRule.h"
#include "nsIDOMCSSMediaRule.h"
@ -418,14 +409,6 @@ static const char kDOMStringBundleURL[] =
((NODE_SCRIPTABLE_FLAGS & ~nsIXPCScriptable::CLASSINFO_INTERFACES_ONLY) | \
nsIXPCScriptable::WANT_POSTCREATE)
#define EXTERNAL_OBJ_SCRIPTABLE_FLAGS \
((ELEMENT_SCRIPTABLE_FLAGS & \
~nsIXPCScriptable::USE_JSSTUB_FOR_SETPROPERTY) | \
nsIXPCScriptable::WANT_POSTCREATE | \
nsIXPCScriptable::WANT_GETPROPERTY | \
nsIXPCScriptable::WANT_SETPROPERTY | \
nsIXPCScriptable::WANT_CALL)
#define DOCUMENT_SCRIPTABLE_FLAGS \
(NODE_SCRIPTABLE_FLAGS | \
nsIXPCScriptable::WANT_POSTCREATE | \
@ -656,10 +639,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
DOCUMENT_SCRIPTABLE_FLAGS |
nsIXPCScriptable::WANT_GETPROPERTY)
// HTML element classes
NS_DEFINE_CLASSINFO_DATA(HTMLAppletElement, nsHTMLPluginObjElementSH,
EXTERNAL_OBJ_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(HTMLEmbedElement, nsHTMLPluginObjElementSH,
EXTERNAL_OBJ_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(HTMLFormElement, nsHTMLFormElementSH,
ELEMENT_SCRIPTABLE_FLAGS |
nsIXPCScriptable::WANT_GETPROPERTY |
@ -668,8 +647,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
ELEMENT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(HTMLInputElement, nsElementSH,
ELEMENT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(HTMLObjectElement, nsHTMLPluginObjElementSH,
EXTERNAL_OBJ_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(HTMLSelectElement, nsHTMLSelectElementSH,
ELEMENT_SCRIPTABLE_FLAGS |
nsIXPCScriptable::WANT_SETPROPERTY |
@ -1950,17 +1927,6 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_DOCUMENT_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(HTMLAppletElement, nsIDOMHTMLAppletElement)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLAppletElement)
DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(HTMLEmbedElement, nsIDOMHTMLEmbedElement)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLEmbedElement)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMGetSVGDocument)
DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(HTMLFormElement, nsIDOMHTMLFormElement)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLFormElement)
DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
@ -1978,12 +1944,6 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(HTMLObjectElement, nsIDOMHTMLObjectElement)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLObjectElement)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMGetSVGDocument)
DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(HTMLSelectElement, nsIDOMHTMLSelectElement)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLSelectElement)
DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
@ -7372,405 +7332,6 @@ nsHTMLSelectElementSH::SetProperty(nsIXPConnectWrappedNative *wrapper,
return NS_OK;
}
// HTMLObject/EmbedElement helper
// Keep in mind that it is OK for this to fail to return an instance. Don't return a
// failure result unless something truly exceptional has happened.
// static
nsresult
nsHTMLPluginObjElementSH::GetPluginInstanceIfSafe(nsIXPConnectWrappedNative *wrapper,
JSObject *obj,
JSContext *cx,
nsNPAPIPluginInstance **_result)
{
*_result = nullptr;
nsCOMPtr<nsIContent> content;
if (wrapper) {
content = do_QueryWrappedNative(wrapper, obj);
} else {
nsISupports* supports;
if (XPCConvert::GetISupportsFromJSObject(obj, &supports)) {
content = do_QueryInterface(supports);
}
}
NS_ENSURE_TRUE(content, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIObjectLoadingContent> objlc(do_QueryInterface(content));
NS_ASSERTION(objlc, "Object nodes must implement nsIObjectLoadingContent");
// The below methods pull the cx off the stack, so make sure they match.
//
// NB: Sometimes there's a null cx on the stack, in which case |cx| is the
// safe JS context. But in that case, IsCallerChrome() will return true,
// so the ensuing expression is short-circuited.
MOZ_ASSERT_IF(nsContentUtils::GetCurrentJSContext(),
cx == nsContentUtils::GetCurrentJSContext());
bool callerIsContentJS = (!nsContentUtils::IsCallerChrome() &&
!nsContentUtils::IsCallerXBL() &&
js::IsContextRunningJS(cx));
return objlc->ScriptRequestPluginInstance(callerIsContentJS,
_result);
}
nsHTMLPluginObjElementSH::SetupProtoChainRunner::SetupProtoChainRunner(
nsIXPConnectWrappedNative* aWrapper,
nsIScriptContext* aScriptContext,
nsObjectLoadingContent* aContent)
: mWrapper(aWrapper)
, mContext(aScriptContext)
, mContent(aContent)
{
}
NS_IMETHODIMP
nsHTMLPluginObjElementSH::SetupProtoChainRunner::Run()
{
nsCxPusher pusher;
JSContext* cx = mContext ? mContext->GetNativeContext()
: nsContentUtils::GetSafeJSContext();
pusher.Push(cx);
JSObject* obj = nullptr;
JSObject* canonicalProto = nullptr;
if (mWrapper) {
mWrapper->GetJSObject(&obj);
NS_ASSERTION(obj, "Should never be null");
} else {
MOZ_ASSERT(mContent, "Must have mContent if no mWrapper");
nsCOMPtr<nsIContent> content;
CallQueryInterface(mContent.get(), getter_AddRefs(content));
obj = content->GetWrapper();
if (!obj) {
// No need to set up our proto chain if we don't even have an object
return NS_OK;
}
JSAutoCompartment ac(cx, obj);
canonicalProto = static_cast<nsObjectLoadingContent*>(mContent.get())->
GetCanonicalPrototype(cx, JS_GetGlobalForObject(cx, obj));
}
nsHTMLPluginObjElementSH::SetupProtoChain(cx, obj, mWrapper, canonicalProto);
return NS_OK;
}
NS_IMPL_ISUPPORTS1(nsHTMLPluginObjElementSH::SetupProtoChainRunner, nsIRunnable)
// static
nsresult
nsHTMLPluginObjElementSH::SetupProtoChain(JSContext *cx,
JSObject *obj,
nsIXPConnectWrappedNative *wrapper,
JSObject* aCanonicalPrototype)
{
NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
"Shouldn't have gotten in here");
MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
JSAutoRequest ar(cx);
JSAutoCompartment ac(cx, obj);
nsRefPtr<nsNPAPIPluginInstance> pi;
nsresult rv = GetPluginInstanceIfSafe(wrapper, obj, cx, getter_AddRefs(pi));
NS_ENSURE_SUCCESS(rv, rv);
if (!pi) {
// No plugin around for this object.
return NS_OK;
}
JSObject *pi_obj = nullptr; // XPConnect-wrapped peer object, when we get it.
JSObject *pi_proto = nullptr; // 'pi.__proto__'
rv = GetPluginJSObject(cx, obj, pi, &pi_obj, &pi_proto);
NS_ENSURE_SUCCESS(rv, rv);
if (!pi_obj) {
// Didn't get a plugin instance JSObject, nothing we can do then.
return NS_OK;
}
// If we got an xpconnect-wrapped plugin object, set obj's
// prototype's prototype to the scriptable plugin.
JSObject *my_proto = nullptr;
if (wrapper) {
// Get 'this.__proto__'
rv = wrapper->GetJSObjectPrototype(&my_proto);
NS_ENSURE_SUCCESS(rv, rv);
} else {
my_proto = aCanonicalPrototype;
}
MOZ_ASSERT(my_proto);
// Set 'this.__proto__' to pi
if (!::JS_SetPrototype(cx, obj, pi_obj)) {
return NS_ERROR_UNEXPECTED;
}
if (pi_proto && JS_GetClass(pi_proto) != sObjectClass) {
// The plugin wrapper has a proto that's not Object.prototype, set
// 'pi.__proto__.__proto__' to the original 'this.__proto__'
if (pi_proto != my_proto && !::JS_SetPrototype(cx, pi_proto, my_proto)) {
return NS_ERROR_UNEXPECTED;
}
} else {
// 'pi' didn't have a prototype, or pi's proto was
// 'Object.prototype' (i.e. pi is an NPRuntime wrapped JS object)
// set 'pi.__proto__' to the original 'this.__proto__'
if (!::JS_SetPrototype(cx, pi_obj, my_proto)) {
return NS_ERROR_UNEXPECTED;
}
}
// Before this proto dance the objects involved looked like this:
//
// this.__proto__.__proto__
// ^ ^ ^
// | | |__ Object.prototype
// | |
// | |__ xpc embed wrapper proto (shared)
// |
// |__ xpc wrapped native embed node
//
// pi.__proto__
// ^ ^
// | |__ Object.prototype
// |
// |__ Plugin NPRuntime JS object wrapper
//
// Now, after the above prototype setup the prototype chain should
// look like this:
//
// this.__proto__.__proto__.__proto__
// ^ ^ ^ ^
// | | | |__ Object.prototype
// | | |
// | | |__ xpc embed wrapper proto (shared)
// | |
// | |__ Plugin NPRuntime JS object wrapper
// |
// |__ xpc wrapped native embed node
//
return NS_OK;
}
NS_IMETHODIMP
nsHTMLPluginObjElementSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
JSObject *globalObj, JSObject **parentObj)
{
nsresult rv = nsElementSH::PreCreate(nativeObj, cx, globalObj, parentObj);
// For now we don't support slim wrappers for plugins.
return rv == NS_SUCCESS_ALLOW_SLIM_WRAPPERS ? NS_OK : rv;
}
NS_IMETHODIMP
nsHTMLPluginObjElementSH::PostCreate(nsIXPConnectWrappedNative *wrapper,
JSContext *cx, JSObject *obj)
{
if (nsContentUtils::IsSafeToRunScript()) {
#ifdef DEBUG
nsresult rv =
#endif
SetupProtoChain(cx, obj, wrapper);
// If SetupProtoChain failed then we're in real trouble. We're about to fail
// PostCreate but it's more than likely that we handed our (now invalid)
// wrapper to someone already. Bug 429442 is an example of the kind of crash
// that can result from such a situation. We'll return NS_OK for the time
// being and hope for the best.
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "SetupProtoChain failed!");
}
else {
// This may be null if the JS context is not a DOM context. That's ok, we'll
// use the safe context from XPConnect in the runnable.
nsCOMPtr<nsIScriptContext> scriptContext = GetScriptContextFromJSContext(cx);
nsRefPtr<SetupProtoChainRunner> runner =
new SetupProtoChainRunner(wrapper, scriptContext, nullptr);
nsContentUtils::AddScriptRunner(runner);
}
return nsElementSH::PostCreate(wrapper, cx, obj);
}
NS_IMETHODIMP
nsHTMLPluginObjElementSH::PostTransplant(nsIXPConnectWrappedNative *wrapper,
JSContext *cx, JSObject *obj)
{
// Call through to PostCreate to do the prototype setup all over again. We
// may reuse the same prototype, in which case our prototype will be a wrapped
// version of the original.
nsresult rv = PostCreate(wrapper, cx, obj);
if (NS_FAILED(rv)) {
NS_WARNING("Calling PostCreate during PostTransplant for plugin element failed.");
}
return NS_OK;
}
NS_IMETHODIMP
nsHTMLPluginObjElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
JSContext *cx, JSObject *obj, jsid id,
jsval *vp, bool *_retval)
{
JSAutoRequest ar(cx);
JSObject *pi_obj;
if (!::JS_GetPrototype(cx, obj, &pi_obj)) {
return NS_ERROR_UNEXPECTED;
}
if (MOZ_UNLIKELY(!pi_obj)) {
return NS_OK;
}
JSBool found = false;
if (!ObjectIsNativeWrapper(cx, obj)) {
*_retval = ::JS_HasPropertyById(cx, pi_obj, id, &found);
if (!*_retval) {
return NS_ERROR_UNEXPECTED;
}
}
if (found) {
*_retval = ::JS_GetPropertyById(cx, pi_obj, id, vp);
return *_retval ? NS_SUCCESS_I_DID_SOMETHING : NS_ERROR_FAILURE;
}
return NS_OK;
}
NS_IMETHODIMP
nsHTMLPluginObjElementSH::SetProperty(nsIXPConnectWrappedNative *wrapper,
JSContext *cx, JSObject *obj, jsid id,
jsval *vp, bool *_retval)
{
JSAutoRequest ar(cx);
JSObject *pi_obj;
if (!::JS_GetPrototype(cx, obj, &pi_obj)) {
return NS_ERROR_UNEXPECTED;
}
if (MOZ_UNLIKELY(!pi_obj)) {
return NS_OK;
}
JSBool found = false;
if (!ObjectIsNativeWrapper(cx, obj)) {
*_retval = ::JS_HasPropertyById(cx, pi_obj, id, &found);
if (!*_retval) {
return NS_ERROR_UNEXPECTED;
}
}
if (found) {
*_retval = ::JS_SetPropertyById(cx, pi_obj, id, vp);
return *_retval ? NS_SUCCESS_I_DID_SOMETHING : NS_ERROR_FAILURE;
}
return NS_OK;
}
NS_IMETHODIMP
nsHTMLPluginObjElementSH::Call(nsIXPConnectWrappedNative *wrapper,
JSContext *cx, JSObject *obj, uint32_t argc,
jsval *argv, jsval *vp, bool *_retval)
{
// XPConnect passes us the XPConnect wrapper JSObject as obj, and
// not the 'this' parameter that the JS engine passes in. Pass in
// the real this parameter from JS (argv[-1]) here.
return DoCall(wrapper, cx, obj, argc, argv, vp, argv[-1], _retval);
}
nsresult
nsHTMLPluginObjElementSH::DoCall(nsIXPConnectWrappedNative *wrapper,
JSContext *cx, JSObject *obj, uint32_t argc,
jsval *argv, jsval *vp, jsval thisVal,
bool *_retval)
{
nsRefPtr<nsNPAPIPluginInstance> 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
// this object, throw.
if (ObjectIsNativeWrapper(cx, obj) || !pi) {
return NS_ERROR_NOT_AVAILABLE;
}
JSObject *pi_obj = nullptr;
JSObject *pi_proto = nullptr;
rv = GetPluginJSObject(cx, obj, pi, &pi_obj, &pi_proto);
NS_ENSURE_SUCCESS(rv, rv);
if (!pi) {
return NS_ERROR_NOT_AVAILABLE;
}
// XPConnect passes us the XPConnect wrapper JSObject as obj, and
// not the 'this' parameter that the JS engine passes in. Pass in
// the real this parameter from JS (argv[-1]) here.
JSAutoRequest ar(cx);
*_retval = ::JS::Call(cx, thisVal, pi_obj, argc, argv, vp);
if (*_retval) {
Telemetry::Accumulate(Telemetry::PLUGIN_CALLED_DIRECTLY, true);
}
return NS_OK;
}
nsresult
nsHTMLPluginObjElementSH::GetPluginJSObject(JSContext *cx, JSObject *obj,
nsNPAPIPluginInstance *plugin_inst,
JSObject **plugin_obj,
JSObject **plugin_proto)
{
*plugin_obj = nullptr;
*plugin_proto = nullptr;
JSAutoRequest ar(cx);
// NB: We need an AutoEnterCompartment because we can be called from
// nsObjectFrame when the plugin loads after the JS object for our content
// node has been created.
JSAutoCompartment ac(cx, obj);
if (plugin_inst) {
plugin_inst->GetJSObject(cx, plugin_obj);
if (*plugin_obj) {
if (!::JS_GetPrototype(cx, *plugin_obj, plugin_proto)) {
return NS_ERROR_UNEXPECTED;
}
}
}
return NS_OK;
}
NS_IMETHODIMP
nsHTMLPluginObjElementSH::NewResolve(nsIXPConnectWrappedNative *wrapper,
JSContext *cx, JSObject *obj, jsid id,
uint32_t flags, JSObject **objp,
bool *_retval)
{
// Make sure the plugin instance is loaded and instantiated, if
// possible.
nsRefPtr<nsNPAPIPluginInstance> pi;
nsresult rv = GetPluginInstanceIfSafe(wrapper, obj, cx, getter_AddRefs(pi));
NS_ENSURE_SUCCESS(rv, rv);
return nsElementSH::NewResolve(wrapper, cx, obj, id, flags, objp,
_retval);
}
// Plugin helper
nsISupports*

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

@ -765,89 +765,6 @@ public:
}
};
// HTMLEmbed/Object/AppletElement helper
class nsHTMLPluginObjElementSH : public nsElementSH
{
protected:
nsHTMLPluginObjElementSH(nsDOMClassInfoData* aData)
: nsElementSH(aData)
{
}
virtual ~nsHTMLPluginObjElementSH()
{
}
// Passing a null aWrapper is fine for WebIDL objects
static nsresult GetPluginInstanceIfSafe(nsIXPConnectWrappedNative *aWrapper,
JSObject *obj,
JSContext *cx,
nsNPAPIPluginInstance **aResult);
static nsresult GetPluginJSObject(JSContext *cx, JSObject *obj,
nsNPAPIPluginInstance *plugin_inst,
JSObject **plugin_obj,
JSObject **plugin_proto);
public:
NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, uint32_t flags,
JSObject **objp, bool *_retval);
NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
JSObject *globalObj, JSObject **parentObj);
NS_IMETHOD PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj);
NS_IMETHOD PostTransplant(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj);
NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, jsval *vp, bool *_retval);
NS_IMETHOD SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, jsval *vp, bool *_retval);
NS_IMETHOD Call(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, uint32_t argc, jsval *argv, jsval *vp,
bool *_retval);
static nsresult SetupProtoChain(JSContext *cx, JSObject *obj,
nsIXPConnectWrappedNative *wrapper = nullptr,
JSObject *aCanonicalProto = nullptr);
// The actual implementation of Call. This allows the caller to
// pass in an explicit "this" value and does not make any
// assumptions about negative indices into argv.
static nsresult DoCall(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, uint32_t argc, jsval *argv, jsval *vp,
jsval thisVal, bool *_retval);
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
{
return new nsHTMLPluginObjElementSH(aData);
}
class SetupProtoChainRunner MOZ_FINAL : public nsIRunnable
{
public:
NS_DECL_ISUPPORTS
// wrapper can be null, but then aContent must be non-null
SetupProtoChainRunner(nsIXPConnectWrappedNative* aWrapper,
nsIScriptContext* aScriptContext,
nsObjectLoadingContent* aContent);
NS_IMETHOD Run();
private:
nsCOMPtr<nsIXPConnectWrappedNative> mWrapper;
nsCOMPtr<nsIScriptContext> mContext;
// We store an nsIObjectLoadingContent because we can
// unambiguously refcount that.
nsRefPtr<nsIObjectLoadingContent> mContent;
};
};
// Plugin helper
class nsPluginSH : public nsNamedArraySH

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

@ -45,12 +45,9 @@ DOMCI_CLASS(DeviceRotationRate)
DOMCI_CLASS(HTMLDocument)
// HTML element classes
DOMCI_CLASS(HTMLAppletElement)
DOMCI_CLASS(HTMLEmbedElement)
DOMCI_CLASS(HTMLFormElement)
DOMCI_CLASS(HTMLIFrameElement)
DOMCI_CLASS(HTMLInputElement)
DOMCI_CLASS(HTMLObjectElement)
DOMCI_CLASS(HTMLSelectElement)
DOMCI_CLASS(ValidityState)