mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-01 05:48:26 +00:00
Bug 648801 (new DOM list bindings) - Set up prototypes and constructors. r=bz/jst/mrbkap.
--HG-- extra : rebase_source : acf503d1c93a333ba8ef14d0c25160adabbccd4a
This commit is contained in:
parent
40d23963c2
commit
ea0499b427
@ -603,6 +603,7 @@ DOMCI_DATA(DOMConstructor, void)
|
||||
0, \
|
||||
PR_FALSE, \
|
||||
PR_FALSE, \
|
||||
NULL, \
|
||||
NS_DEFINE_CLASSINFO_DATA_DEBUG(_class) \
|
||||
},
|
||||
|
||||
@ -619,6 +620,7 @@ DOMCI_DATA(DOMConstructor, void)
|
||||
0, \
|
||||
PR_TRUE, \
|
||||
PR_FALSE, \
|
||||
NULL, \
|
||||
NS_DEFINE_CLASSINFO_DATA_DEBUG(_class) \
|
||||
},
|
||||
|
||||
@ -1571,6 +1573,7 @@ jsid nsDOMClassInfo::sParent_id = JSID_VOID;
|
||||
jsid nsDOMClassInfo::sScrollbars_id = JSID_VOID;
|
||||
jsid nsDOMClassInfo::sLocation_id = JSID_VOID;
|
||||
jsid nsDOMClassInfo::sConstructor_id = JSID_VOID;
|
||||
jsid nsDOMClassInfo::sPrototype_id = JSID_VOID;
|
||||
jsid nsDOMClassInfo::s_content_id = JSID_VOID;
|
||||
jsid nsDOMClassInfo::sContent_id = JSID_VOID;
|
||||
jsid nsDOMClassInfo::sMenubar_id = JSID_VOID;
|
||||
@ -1834,6 +1837,7 @@ nsDOMClassInfo::DefineStaticJSVals(JSContext *cx)
|
||||
SET_JSID_TO_STRING(sScrollbars_id, cx, "scrollbars");
|
||||
SET_JSID_TO_STRING(sLocation_id, cx, "location");
|
||||
SET_JSID_TO_STRING(sConstructor_id, cx, "constructor");
|
||||
SET_JSID_TO_STRING(sPrototype_id, cx, "prototype");
|
||||
SET_JSID_TO_STRING(s_content_id, cx, "_content");
|
||||
SET_JSID_TO_STRING(sContent_id, cx, "content");
|
||||
SET_JSID_TO_STRING(sMenubar_id, cx, "menubar");
|
||||
@ -4181,6 +4185,8 @@ nsDOMClassInfo::Init()
|
||||
sDisableGlobalScopePollutionSupport =
|
||||
Preferences::GetBool("browser.dom.global_scope_pollution.disabled");
|
||||
|
||||
xpc::dom::Register(sClassInfoData);
|
||||
|
||||
sIsInitialized = PR_TRUE;
|
||||
|
||||
return NS_OK;
|
||||
@ -4814,6 +4820,7 @@ nsDOMClassInfo::ShutDown()
|
||||
sScrollbars_id = JSID_VOID;
|
||||
sLocation_id = JSID_VOID;
|
||||
sConstructor_id = JSID_VOID;
|
||||
sPrototype_id = JSID_VOID;
|
||||
s_content_id = JSID_VOID;
|
||||
sContent_id = JSID_VOID;
|
||||
sMenubar_id = JSID_VOID;
|
||||
@ -6163,6 +6170,17 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
|
||||
}
|
||||
}
|
||||
|
||||
// Lookup new DOM bindings.
|
||||
if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
|
||||
xpc::dom::DefineInterface define =
|
||||
sClassInfoData[name_struct->mDOMClassInfoID].mDefineDOMInterface;
|
||||
if (define && xpc::dom::DefineConstructor(cx, obj, define)) {
|
||||
*did_resolve = true;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the XPConnect prototype for our classinfo, PostCreateProto will
|
||||
// set up the prototype chain.
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> proto_holder;
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "xpcpublic.h"
|
||||
|
||||
namespace mozilla {
|
||||
class DOMSVGLengthList;
|
||||
@ -100,6 +101,8 @@ struct nsDOMClassInfoData
|
||||
PRUint32 mInterfacesBitmap;
|
||||
bool mChromeOnly;
|
||||
bool mDisabled;
|
||||
// For new style DOM bindings.
|
||||
xpc::dom::DefineInterface mDefineDOMInterface;
|
||||
#ifdef NS_DEBUG
|
||||
PRUint32 mDebugID;
|
||||
#endif
|
||||
@ -251,6 +254,7 @@ public:
|
||||
static jsid sScrollbars_id;
|
||||
static jsid sLocation_id;
|
||||
static jsid sConstructor_id;
|
||||
static jsid sPrototype_id;
|
||||
static jsid s_content_id;
|
||||
static jsid sContent_id;
|
||||
static jsid sMenubar_id;
|
||||
|
@ -68,6 +68,7 @@
|
||||
#include "IDBKeyRange.h"
|
||||
#include "IndexedDatabaseManager.h"
|
||||
#include "LazyIdleThread.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include "AsyncConnectionHelper.h"
|
||||
#include "IDBEvents.h"
|
||||
#include "IDBTransaction.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
USING_INDEXEDDB_NAMESPACE
|
||||
|
||||
|
@ -83,8 +83,11 @@ NodeList<T>::NodeList()
|
||||
template<class T>
|
||||
NodeList<T> NodeList<T>::instance;
|
||||
|
||||
JSBool
|
||||
interface_hasInstance(JSContext *cx, JSObject *obj, const js::Value *vp, JSBool *bp);
|
||||
|
||||
template<>
|
||||
Class NodeList<nsINodeList>::sProtoClass = {
|
||||
Class NodeList<nsINodeList>::sInterfaceClass = {
|
||||
"NodeList",
|
||||
0,
|
||||
JS_PropertyStub, /* addProperty */
|
||||
@ -93,7 +96,14 @@ Class NodeList<nsINodeList>::sProtoClass = {
|
||||
JS_StrictPropertyStub, /* setProperty */
|
||||
JS_EnumerateStub,
|
||||
JS_ResolveStub,
|
||||
JS_ConvertStub
|
||||
JS_ConvertStub,
|
||||
NULL, /* finalize */
|
||||
NULL, /* reserved0 */
|
||||
NULL, /* checkAccess */
|
||||
NULL, /* call */
|
||||
NULL, /* construct */
|
||||
NULL, /* xdrObject */
|
||||
interface_hasInstance
|
||||
};
|
||||
|
||||
template<>
|
||||
@ -102,7 +112,7 @@ NodeList<nsINodeList>::Methods NodeList<nsINodeList>::sProtoMethods[] = {
|
||||
};
|
||||
|
||||
template<>
|
||||
Class NodeList<nsIHTMLCollection>::sProtoClass = {
|
||||
Class NodeList<nsIHTMLCollection>::sInterfaceClass = {
|
||||
"HTMLCollection",
|
||||
0,
|
||||
JS_PropertyStub, /* addProperty */
|
||||
@ -111,7 +121,14 @@ Class NodeList<nsIHTMLCollection>::sProtoClass = {
|
||||
JS_StrictPropertyStub, /* setProperty */
|
||||
JS_EnumerateStub,
|
||||
JS_ResolveStub,
|
||||
JS_ConvertStub
|
||||
JS_ConvertStub,
|
||||
NULL, /* finalize */
|
||||
NULL, /* reserved0 */
|
||||
NULL, /* checkAccess */
|
||||
NULL, /* call */
|
||||
NULL, /* construct */
|
||||
NULL, /* xdrObject */
|
||||
interface_hasInstance
|
||||
};
|
||||
|
||||
template<>
|
||||
@ -124,6 +141,24 @@ NodeList<nsIHTMLCollection>::Methods NodeList<nsIHTMLCollection>::sProtoMethods[
|
||||
{ nsDOMClassInfo::sNamedItem_id, &namedItem, 1 }
|
||||
};
|
||||
|
||||
void
|
||||
Register(nsDOMClassInfoData *aData)
|
||||
{
|
||||
#define REGISTER_PROTO(_dom_class, T) \
|
||||
aData[eDOMClassInfo_##_dom_class##_id].mDefineDOMInterface = NodeList<T>::getPrototype
|
||||
|
||||
REGISTER_PROTO(NodeList, nsINodeList);
|
||||
REGISTER_PROTO(HTMLCollection, nsIHTMLCollection);
|
||||
|
||||
#undef REGISTER_PROTO
|
||||
}
|
||||
|
||||
bool
|
||||
DefineConstructor(JSContext *cx, JSObject *obj, DefineInterface aDefine)
|
||||
{
|
||||
return !!aDefine(cx, XPCWrappedNativeScope::FindInJSObjectScope(cx, obj));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T*
|
||||
NodeList<T>::getNodeList(JSObject *obj)
|
||||
@ -264,47 +299,109 @@ NodeList<nsIHTMLCollection>::namedItem(JSContext *cx, uintN argc, jsval *vp)
|
||||
return namedItem(cx, obj, &argv[0], vp);
|
||||
}
|
||||
|
||||
JSBool
|
||||
interface_hasInstance(JSContext *cx, JSObject *obj, const js::Value *vp, JSBool *bp)
|
||||
{
|
||||
if (vp->isObject()) {
|
||||
jsval prototype;
|
||||
if (!JS_GetPropertyById(cx, obj, nsDOMClassInfo::sPrototype_id, &prototype) ||
|
||||
JSVAL_IS_PRIMITIVE(prototype)) {
|
||||
JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
|
||||
JSMSG_THROW_TYPE_ERROR);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
JSObject *other = &vp->toObject();
|
||||
if (instanceIsProxy(other)) {
|
||||
ProxyHandler *handler = static_cast<ProxyHandler*>(js::GetProxyHandler(other));
|
||||
if (handler->isInstanceOf(JSVAL_TO_OBJECT(prototype))) {
|
||||
*bp = JS_TRUE;
|
||||
}
|
||||
else {
|
||||
JSObject *protoObj = JSVAL_TO_OBJECT(prototype);
|
||||
JSObject *proto = other;
|
||||
while ((proto = JS_GetPrototype(cx, proto))) {
|
||||
if (proto == protoObj) {
|
||||
*bp = JS_TRUE;
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
*bp = JS_FALSE;
|
||||
}
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
*bp = JS_FALSE;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
JSObject *
|
||||
NodeList<T>::getPrototype(JSContext *cx, XPCWrappedNativeScope *scope)
|
||||
{
|
||||
nsDataHashtable<nsIDHashKey, JSObject*> &cache =
|
||||
nsDataHashtable<nsDepCharHashKey, JSObject*> &cache =
|
||||
scope->GetCachedDOMPrototypes();
|
||||
|
||||
JSObject *proto;
|
||||
JSObject *interfacePrototype;
|
||||
if (cache.IsInitialized()) {
|
||||
if (cache.Get(NS_GET_TEMPLATE_IID(T), &proto))
|
||||
return proto;
|
||||
if (cache.Get(sInterfaceClass.name, &interfacePrototype))
|
||||
return interfacePrototype;
|
||||
}
|
||||
else if (!cache.Init()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
proto = JS_NewObject(cx, Jsvalify(&sProtoClass), NULL, NULL);
|
||||
if (!proto)
|
||||
JSObject *global = scope->GetGlobalJSObject();
|
||||
|
||||
// We need to pass the object prototype to JS_NewObject. If we pass NULL then the JS engine
|
||||
// will look up a prototype on the global by using the class' name and we'll recurse into
|
||||
// getPrototype.
|
||||
JSObject* proto;
|
||||
if (!js_GetClassPrototype(cx, global, JSProto_Object, &proto))
|
||||
return NULL;
|
||||
|
||||
if (!JS_DefinePropertyById(cx, proto, nsDOMClassInfo::sLength_id, JSVAL_VOID,
|
||||
length_getter, NULL,
|
||||
interfacePrototype = JS_NewObject(cx, NULL, proto, global);
|
||||
if (!interfacePrototype)
|
||||
return NULL;
|
||||
|
||||
if (!JS_DefinePropertyById(cx, interfacePrototype, nsDOMClassInfo::sLength_id,
|
||||
JSVAL_VOID, length_getter, NULL,
|
||||
JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_SHARED))
|
||||
return NULL;
|
||||
|
||||
for (size_t n = 0; n < NS_ARRAY_LENGTH(sProtoMethods); ++n) {
|
||||
jsid id = sProtoMethods[n].id;
|
||||
JSFunction *fun = JS_NewFunctionById(cx, sProtoMethods[n].native, sProtoMethods[n].nargs,
|
||||
0, js::GetObjectParent(proto), id);
|
||||
0, js::GetObjectParent(interfacePrototype), id);
|
||||
if (!fun)
|
||||
return NULL;
|
||||
JSObject *funobj = JS_GetFunctionObject(fun);
|
||||
if (!JS_DefinePropertyById(cx, proto, id, OBJECT_TO_JSVAL(funobj),
|
||||
if (!JS_DefinePropertyById(cx, interfacePrototype, id, OBJECT_TO_JSVAL(funobj),
|
||||
NULL, NULL, JSPROP_ENUMERATE))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!cache.Put(NS_GET_TEMPLATE_IID(T), proto))
|
||||
JSObject *interface = JS_NewObject(cx, Jsvalify(&sInterfaceClass), NULL, global);
|
||||
if (!interface ||
|
||||
!JS_DefinePropertyById(cx, interface, nsDOMClassInfo::sPrototype_id,
|
||||
OBJECT_TO_JSVAL(interfacePrototype), nsnull, nsnull,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY))
|
||||
return NULL;
|
||||
|
||||
return proto;
|
||||
if (!JS_DefinePropertyById(cx, interfacePrototype, nsDOMClassInfo::sConstructor_id,
|
||||
OBJECT_TO_JSVAL(interface), nsnull, nsnull, 0))
|
||||
return NULL;
|
||||
|
||||
if (!JS_DefineProperty(cx, global, sInterfaceClass.name, OBJECT_TO_JSVAL(interface), NULL,
|
||||
NULL, 0))
|
||||
return NULL;
|
||||
|
||||
if (!cache.Put(sInterfaceClass.name, interfacePrototype))
|
||||
return NULL;
|
||||
|
||||
return interfacePrototype;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
@ -740,7 +837,7 @@ template<class T>
|
||||
bool
|
||||
NodeList<T>::hasInstance(JSContext *cx, JSObject *proxy, const Value *vp, bool *bp)
|
||||
{
|
||||
*bp = vp->isObject() && js::GetObjectClass(&vp->toObject()) == &sProtoClass;
|
||||
*bp = vp->isObject() && js::GetObjectClass(&vp->toObject()) == &sInterfaceClass;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -50,9 +50,19 @@ class nsIHTMLCollection;
|
||||
namespace xpc {
|
||||
namespace dom {
|
||||
|
||||
class NodeListBase : public js::ProxyHandler {
|
||||
class ProxyHandler : public js::ProxyHandler {
|
||||
protected:
|
||||
ProxyHandler() : js::ProxyHandler(ProxyFamily())
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
NodeListBase() : js::ProxyHandler(ProxyFamily()) {}
|
||||
virtual bool isInstanceOf(JSObject *prototype) = 0;
|
||||
};
|
||||
|
||||
class NodeListBase : public ProxyHandler {
|
||||
public:
|
||||
NodeListBase() : ProxyHandler() {}
|
||||
|
||||
static JSObject *create(JSContext *cx, XPCWrappedNativeScope *scope,
|
||||
nsINodeList *aNodeList);
|
||||
@ -66,9 +76,11 @@ public:
|
||||
*/
|
||||
template<class T>
|
||||
class NodeList : public NodeListBase {
|
||||
friend void Register(nsDOMClassInfoData *aData);
|
||||
|
||||
static NodeList instance;
|
||||
|
||||
static js::Class sProtoClass;
|
||||
static js::Class sInterfaceClass;
|
||||
|
||||
struct Methods {
|
||||
jsid &id;
|
||||
@ -136,6 +148,10 @@ class NodeList : public NodeListBase {
|
||||
static bool objIsNodeList(JSObject *obj) {
|
||||
return js::IsProxy(obj) && js::GetProxyHandler(obj) == &instance;
|
||||
}
|
||||
virtual bool isInstanceOf(JSObject *prototype)
|
||||
{
|
||||
return js::GetObjectClass(prototype) == &sInterfaceClass;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1600,7 +1600,7 @@ public:
|
||||
XPCContext *GetContext() { return mContext; }
|
||||
void SetContext(XPCContext *xpcc) { mContext = nsnull; }
|
||||
|
||||
nsDataHashtable<nsIDHashKey, JSObject*>& GetCachedDOMPrototypes()
|
||||
nsDataHashtable<nsDepCharHashKey, JSObject*>& GetCachedDOMPrototypes()
|
||||
{
|
||||
return mCachedDOMPrototypes;
|
||||
}
|
||||
@ -1656,7 +1656,7 @@ private:
|
||||
// about, since all of our scope objects are verified as not doing that.
|
||||
nsIScriptObjectPrincipal* mScriptObjectPrincipal;
|
||||
|
||||
nsDataHashtable<nsIDHashKey, JSObject*> mCachedDOMPrototypes;
|
||||
nsDataHashtable<nsDepCharHashKey, JSObject*> mCachedDOMPrototypes;
|
||||
};
|
||||
|
||||
JSObject* xpc_CloneJSFunction(XPCCallContext &ccx, JSObject *funobj,
|
||||
|
@ -54,6 +54,7 @@
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsIPrincipal;
|
||||
struct nsDOMClassInfoData;
|
||||
|
||||
static const uint32 XPC_GC_COLOR_BLACK = 0;
|
||||
static const uint32 XPC_GC_COLOR_GRAY = 1;
|
||||
@ -284,6 +285,14 @@ enum {
|
||||
JSPROXYSLOT_EXPANDO = 1
|
||||
};
|
||||
|
||||
typedef JSObject*
|
||||
(*DefineInterface)(JSContext *cx, XPCWrappedNativeScope *scope);
|
||||
|
||||
void
|
||||
Register(nsDOMClassInfoData *aData);
|
||||
extern bool
|
||||
DefineConstructor(JSContext *cx, JSObject *obj, DefineInterface aDefine);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -921,7 +921,7 @@ XPCWrappedNativeScope::RemoveWrappedNativeProtos()
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
TraceDOMPrototype(const nsID& aKey, JSObject* aData, void* aClosure)
|
||||
TraceDOMPrototype(const char* aKey, JSObject* aData, void* aClosure)
|
||||
{
|
||||
JSTracer *trc = static_cast<JSTracer*>(aClosure);
|
||||
JS_CALL_OBJECT_TRACER(trc, aData, "DOM prototype");
|
||||
|
Loading…
x
Reference in New Issue
Block a user