Fix for bug 802739 (Make parent wrapping for DOM bindings fall back to XPConnect for nsISupports classes).

--HG--
extra : rebase_source : 212a49060710b5b3791203b9472c9efcad578a58
This commit is contained in:
Peter Van der Beken 2012-10-19 09:33:18 +02:00
parent a69ce442c1
commit 350fbbbaa6

View File

@ -743,26 +743,96 @@ bool
WrapCallbackInterface(JSContext *cx, JSObject *scope, nsISupports* callback, WrapCallbackInterface(JSContext *cx, JSObject *scope, nsISupports* callback,
JS::Value* vp); JS::Value* vp);
// This checks whether class T implements WrapObject itself, if so then #ifdef _MSC_VER
// HasWrapObject<T>::Value will be true. Note that if T inherits WrapObject from #define HAS_MEMBER_CHECK(_name) \
// a base class but doesn't override it then HasWrapObject<T>::Value will be template<typename V> static yes& Check(char (*)[(&V::_name == 0) + 1])
// false. This is a little annoying in some cases (multiple C++ classes using #else
// the same binding), but it saves us in the case where a class inherits from #define HAS_MEMBER_CHECK(_name) \
// nsWrapperCache but doesn't actually override WrapObject. For now we assume template<typename V> static yes& Check(char (*)[sizeof(&V::_name) + 1])
// that HasWrapObject<T>::Value being false means we have an nsISupports object. #endif
#define HAS_MEMBER(_name) \
template<typename T> \
class Has##_name##Member { \
typedef char yes[1]; \
typedef char no[2]; \
HAS_MEMBER_CHECK(_name); \
template<typename V> static no& Check(...); \
\
public: \
static bool const Value = sizeof(Check<T>(nullptr)) == sizeof(yes); \
};
HAS_MEMBER(AddRef)
HAS_MEMBER(Release)
HAS_MEMBER(QueryInterface)
template<typename T>
struct IsRefCounted
{
static bool const Value = HasAddRefMember<T>::Value &&
HasReleaseMember<T>::Value;
};
template<typename T>
struct IsISupports
{
static bool const Value = IsRefCounted<T>::Value &&
HasQueryInterfaceMember<T>::Value;
};
HAS_MEMBER(WrapObject)
// HasWrapObject<T>::Value will be true if T has a WrapObject member but it's
// not nsWrapperCache::WrapObject.
template<typename T> template<typename T>
struct HasWrapObject struct HasWrapObject
{ {
private: private:
typedef char yes[1]; typedef char yes[1];
typedef char no[2]; typedef char no[2];
typedef JSObject* (T::*WrapObject)(JSContext*, JSObject*, bool*); typedef JSObject* (nsWrapperCache::*WrapObject)(JSContext*, JSObject*, bool*);
template<typename U, U> struct SFINAE; template<typename U, U> struct SFINAE;
template <typename V> static yes& Check(SFINAE<WrapObject, &V::WrapObject>*); template <typename V> static no& Check(SFINAE<WrapObject, &V::WrapObject>*);
template <typename V> static no& Check(...); template <typename V> static yes& Check(...);
public: public:
static bool const Value = sizeof(Check<T>(nullptr)) == sizeof(yes); static bool const Value = HasWrapObjectMember<T>::Value &&
sizeof(Check<T>(nullptr)) == sizeof(yes);
};
template<typename T>
static inline JSObject*
WrapNativeISupportsParent(JSContext* cx, JSObject* scope, T* p,
nsWrapperCache* cache)
{
qsObjectHelper helper(ToSupports(p), cache);
JS::Value v;
return XPCOMObjectToJsval(cx, scope, helper, nullptr, false, &v) ?
JSVAL_TO_OBJECT(v) :
nullptr;
}
template<typename T, bool isISupports=IsISupports<T>::Value >
struct WrapNativeParentFallback
{
static inline JSObject* Wrap(JSContext* cx, JSObject* scope, T* parent,
nsWrapperCache* cache)
{
MOZ_NOT_REACHED("Don't know how to deal with triedToWrap == false for "
"non-nsISupports classes");
return nullptr;
}
};
template<typename T >
struct WrapNativeParentFallback<T, true >
{
static inline JSObject* Wrap(JSContext* cx, JSObject* scope, T* parent,
nsWrapperCache* cache)
{
return WrapNativeISupportsParent(cx, scope, parent, cache);
}
}; };
template<typename T, bool hasWrapObject=HasWrapObject<T>::Value > template<typename T, bool hasWrapObject=HasWrapObject<T>::Value >
@ -779,12 +849,16 @@ struct WrapNativeParentHelper
} }
bool triedToWrap; bool triedToWrap;
return parent->WrapObject(cx, scope, &triedToWrap); obj = parent->WrapObject(cx, scope, &triedToWrap);
if (!triedToWrap) {
obj = WrapNativeParentFallback<T>::Wrap(cx, scope, parent, cache);
}
return obj;
} }
}; };
template<typename T> template<typename T>
struct WrapNativeParentHelper<T, false> struct WrapNativeParentHelper<T, false >
{ {
static inline JSObject* Wrap(JSContext* cx, JSObject* scope, T* parent, static inline JSObject* Wrap(JSContext* cx, JSObject* scope, T* parent,
nsWrapperCache* cache) nsWrapperCache* cache)
@ -792,21 +866,13 @@ struct WrapNativeParentHelper<T, false>
JSObject* obj; JSObject* obj;
if (cache && (obj = cache->GetWrapper())) { if (cache && (obj = cache->GetWrapper())) {
#ifdef DEBUG #ifdef DEBUG
qsObjectHelper helper(ToSupports(parent), cache); NS_ASSERTION(WrapNativeISupportsParent(cx, scope, parent, cache) == obj,
JS::Value debugVal;
bool ok = XPCOMObjectToJsval(cx, scope, helper, NULL, false, &debugVal);
NS_ASSERTION(ok && JSVAL_TO_OBJECT(debugVal) == obj,
"Unexpected object in nsWrapperCache"); "Unexpected object in nsWrapperCache");
#endif #endif
return obj; return obj;
} }
qsObjectHelper helper(ToSupports(parent), cache); return WrapNativeISupportsParent(cx, scope, parent, cache);
JS::Value v;
return XPCOMObjectToJsval(cx, scope, helper, NULL, false, &v) ?
JSVAL_TO_OBJECT(v) :
NULL;
} }
}; };