1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/glue/nsIClassInfoImpl.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,176 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#ifndef nsIClassInfoImpl_h__ 1.9 +#define nsIClassInfoImpl_h__ 1.10 + 1.11 +#include "mozilla/Alignment.h" 1.12 +#include "mozilla/Assertions.h" 1.13 +#include "mozilla/MacroArgs.h" 1.14 +#include "mozilla/MacroForEach.h" 1.15 +#include "nsIClassInfo.h" 1.16 +#include "nsISupportsImpl.h" 1.17 + 1.18 +#include <new> 1.19 + 1.20 +/** 1.21 + * This header file provides macros which help you make your class implement 1.22 + * nsIClassInfo. Implementing nsIClassInfo is particularly helpful if you have 1.23 + * a C++ class which implements multiple interfaces and which you access from 1.24 + * JavaScript. If that class implements nsIClassInfo, the JavaScript code 1.25 + * won't have to call QueryInterface on instances of the class; all methods 1.26 + * from all interfaces returned by GetInterfaces() will be available 1.27 + * automagically. 1.28 + * 1.29 + * Here's all you need to do. Given a class 1.30 + * 1.31 + * class nsFooBar : public nsIFoo, public nsIBar { }; 1.32 + * 1.33 + * you should already have the following nsISupports implementation in its cpp 1.34 + * file: 1.35 + * 1.36 + * NS_IMPL_ISUPPORTS(nsFooBar, nsIFoo, nsIBar). 1.37 + * 1.38 + * Change this to 1.39 + * 1.40 + * NS_IMPL_CLASSINFO(nsFooBar, nullptr, 0, NS_FOOBAR_CID) 1.41 + * NS_IMPL_ISUPPORTS_CI(nsFooBar, nsIFoo, nsIBar) 1.42 + * 1.43 + * If nsFooBar is threadsafe, change the 0 above to nsIClassInfo::THREADSAFE. 1.44 + * If it's a singleton, use nsIClassInfo::SINGLETON. The full list of flags is 1.45 + * in nsIClassInfo.idl. 1.46 + * 1.47 + * The nullptr parameter is there so you can pass a function for converting 1.48 + * from an XPCOM object to a scriptable helper. Unless you're doing 1.49 + * specialized JS work, you can probably leave this as nullptr. 1.50 + * 1.51 + * This file also defines the NS_IMPL_QUERY_INTERFACE_CI macro, which you can 1.52 + * use to replace NS_IMPL_QUERY_INTERFACE, if you use that instead of 1.53 + * NS_IMPL_ISUPPORTS. 1.54 + * 1.55 + * That's it! The rest is gory details. 1.56 + * 1.57 + * 1.58 + * Notice that nsFooBar didn't need to inherit from nsIClassInfo in order to 1.59 + * "implement" it. However, after adding these macros to nsFooBar, you you can 1.60 + * QueryInterface an instance of nsFooBar to nsIClassInfo. How can this be? 1.61 + * 1.62 + * The answer lies in the NS_IMPL_ISUPPORTS_CI macro. It modifies nsFooBar's 1.63 + * QueryInterface implementation such that, if we ask to QI to nsIClassInfo, it 1.64 + * returns a singleton object associated with the class. (That singleton is 1.65 + * defined by NS_IMPL_CLASSINFO.) So all nsFooBar instances will return the 1.66 + * same object when QI'ed to nsIClassInfo. (You can see this in 1.67 + * NS_IMPL_QUERY_CLASSINFO below.) 1.68 + * 1.69 + * This hack breaks XPCOM's rules, since if you take an instance of nsFooBar, 1.70 + * QI it to nsIClassInfo, and then try to QI to nsIFoo, that will fail. On the 1.71 + * upside, implementing nsIClassInfo doesn't add a vtable pointer to instances 1.72 + * of your class. 1.73 + * 1.74 + * In principal, you can also implement nsIClassInfo by inheriting from the 1.75 + * interface. But some code expects that when it QI's an object to 1.76 + * nsIClassInfo, it gets back a singleton which isn't attached to any 1.77 + * particular object. If a class were to implement nsIClassInfo through 1.78 + * inheritance, that code might QI to nsIClassInfo and keep the resulting 1.79 + * object alive, thinking it was only keeping alive the classinfo singleton, 1.80 + * but in fact keeping a whole instance of the class alive. See, e.g., bug 1.81 + * 658632. 1.82 + * 1.83 + * Unless you specifically need to have a different nsIClassInfo instance for 1.84 + * each instance of your class, you should probably just implement nsIClassInfo 1.85 + * as a singleton. 1.86 + */ 1.87 + 1.88 +class NS_COM_GLUE GenericClassInfo : public nsIClassInfo 1.89 +{ 1.90 +public: 1.91 + struct ClassInfoData 1.92 + { 1.93 + typedef NS_CALLBACK(GetInterfacesProc)(uint32_t* countp, 1.94 + nsIID*** array); 1.95 + typedef NS_CALLBACK(GetLanguageHelperProc)(uint32_t language, 1.96 + nsISupports** helper); 1.97 + 1.98 + GetInterfacesProc getinterfaces; 1.99 + GetLanguageHelperProc getlanguagehelper; 1.100 + uint32_t flags; 1.101 + nsCID cid; 1.102 + }; 1.103 + 1.104 + NS_DECL_ISUPPORTS_INHERITED 1.105 + NS_DECL_NSICLASSINFO 1.106 + 1.107 + GenericClassInfo(const ClassInfoData* data) 1.108 + : mData(data) 1.109 + { } 1.110 + 1.111 +private: 1.112 + const ClassInfoData* mData; 1.113 +}; 1.114 + 1.115 +#define NS_CLASSINFO_NAME(_class) g##_class##_classInfoGlobal 1.116 +#define NS_CI_INTERFACE_GETTER_NAME(_class) _class##_GetInterfacesHelper 1.117 +#define NS_DECL_CI_INTERFACE_GETTER(_class) \ 1.118 + extern NS_IMETHODIMP NS_CI_INTERFACE_GETTER_NAME(_class) \ 1.119 + (uint32_t *, nsIID ***); 1.120 + 1.121 +#define NS_IMPL_CLASSINFO(_class, _getlanguagehelper, _flags, _cid) \ 1.122 + NS_DECL_CI_INTERFACE_GETTER(_class) \ 1.123 + static const GenericClassInfo::ClassInfoData k##_class##ClassInfoData = { \ 1.124 + NS_CI_INTERFACE_GETTER_NAME(_class), \ 1.125 + _getlanguagehelper, \ 1.126 + _flags | nsIClassInfo::SINGLETON_CLASSINFO, \ 1.127 + _cid, \ 1.128 + }; \ 1.129 + mozilla::AlignedStorage2<GenericClassInfo> k##_class##ClassInfoDataPlace; \ 1.130 + nsIClassInfo* NS_CLASSINFO_NAME(_class) = nullptr; 1.131 + 1.132 +#define NS_IMPL_QUERY_CLASSINFO(_class) \ 1.133 + if ( aIID.Equals(NS_GET_IID(nsIClassInfo)) ) { \ 1.134 + if (!NS_CLASSINFO_NAME(_class)) \ 1.135 + NS_CLASSINFO_NAME(_class) = new (k##_class##ClassInfoDataPlace.addr()) \ 1.136 + GenericClassInfo(&k##_class##ClassInfoData); \ 1.137 + foundInterface = NS_CLASSINFO_NAME(_class); \ 1.138 + } else 1.139 + 1.140 +#define NS_CLASSINFO_HELPER_BEGIN(_class, _c) \ 1.141 +NS_IMETHODIMP \ 1.142 +NS_CI_INTERFACE_GETTER_NAME(_class)(uint32_t *count, nsIID ***array) \ 1.143 +{ \ 1.144 + *count = _c; \ 1.145 + *array = (nsIID **)nsMemory::Alloc(sizeof (nsIID *) * _c); \ 1.146 + uint32_t i = 0; 1.147 + 1.148 +#define NS_CLASSINFO_HELPER_ENTRY(_interface) \ 1.149 + (*array)[i++] = (nsIID*)nsMemory::Clone(&NS_GET_IID(_interface), \ 1.150 + sizeof(nsIID)); 1.151 + 1.152 +#define NS_CLASSINFO_HELPER_END \ 1.153 + MOZ_ASSERT(i == *count, "Incorrent number of entries"); \ 1.154 + return NS_OK; \ 1.155 +} 1.156 + 1.157 +#define NS_IMPL_CI_INTERFACE_GETTER(aClass, ...) \ 1.158 + MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__); \ 1.159 + NS_CLASSINFO_HELPER_BEGIN(aClass, \ 1.160 + MOZ_PASTE_PREFIX_AND_ARG_COUNT(/* No prefix */, \ 1.161 + __VA_ARGS__)) \ 1.162 + MOZ_FOR_EACH(NS_CLASSINFO_HELPER_ENTRY, (), (__VA_ARGS__)) \ 1.163 + NS_CLASSINFO_HELPER_END 1.164 + 1.165 +#define NS_IMPL_QUERY_INTERFACE_CI(aClass, ...) \ 1.166 + MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__); \ 1.167 + NS_INTERFACE_MAP_BEGIN(aClass) \ 1.168 + MOZ_FOR_EACH(NS_INTERFACE_MAP_ENTRY, (), (__VA_ARGS__)) \ 1.169 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, MOZ_ARG_1(__VA_ARGS__)) \ 1.170 + NS_IMPL_QUERY_CLASSINFO(aClass) \ 1.171 + NS_INTERFACE_MAP_END 1.172 + 1.173 +#define NS_IMPL_ISUPPORTS_CI(aClass, ...) \ 1.174 + NS_IMPL_ADDREF(aClass) \ 1.175 + NS_IMPL_RELEASE(aClass) \ 1.176 + NS_IMPL_QUERY_INTERFACE_CI(aClass, __VA_ARGS__) \ 1.177 + NS_IMPL_CI_INTERFACE_GETTER(aClass, __VA_ARGS__) 1.178 + 1.179 +#endif // nsIClassInfoImpl_h__