Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | #ifndef nsIClassInfoImpl_h__ |
michael@0 | 6 | #define nsIClassInfoImpl_h__ |
michael@0 | 7 | |
michael@0 | 8 | #include "mozilla/Alignment.h" |
michael@0 | 9 | #include "mozilla/Assertions.h" |
michael@0 | 10 | #include "mozilla/MacroArgs.h" |
michael@0 | 11 | #include "mozilla/MacroForEach.h" |
michael@0 | 12 | #include "nsIClassInfo.h" |
michael@0 | 13 | #include "nsISupportsImpl.h" |
michael@0 | 14 | |
michael@0 | 15 | #include <new> |
michael@0 | 16 | |
michael@0 | 17 | /** |
michael@0 | 18 | * This header file provides macros which help you make your class implement |
michael@0 | 19 | * nsIClassInfo. Implementing nsIClassInfo is particularly helpful if you have |
michael@0 | 20 | * a C++ class which implements multiple interfaces and which you access from |
michael@0 | 21 | * JavaScript. If that class implements nsIClassInfo, the JavaScript code |
michael@0 | 22 | * won't have to call QueryInterface on instances of the class; all methods |
michael@0 | 23 | * from all interfaces returned by GetInterfaces() will be available |
michael@0 | 24 | * automagically. |
michael@0 | 25 | * |
michael@0 | 26 | * Here's all you need to do. Given a class |
michael@0 | 27 | * |
michael@0 | 28 | * class nsFooBar : public nsIFoo, public nsIBar { }; |
michael@0 | 29 | * |
michael@0 | 30 | * you should already have the following nsISupports implementation in its cpp |
michael@0 | 31 | * file: |
michael@0 | 32 | * |
michael@0 | 33 | * NS_IMPL_ISUPPORTS(nsFooBar, nsIFoo, nsIBar). |
michael@0 | 34 | * |
michael@0 | 35 | * Change this to |
michael@0 | 36 | * |
michael@0 | 37 | * NS_IMPL_CLASSINFO(nsFooBar, nullptr, 0, NS_FOOBAR_CID) |
michael@0 | 38 | * NS_IMPL_ISUPPORTS_CI(nsFooBar, nsIFoo, nsIBar) |
michael@0 | 39 | * |
michael@0 | 40 | * If nsFooBar is threadsafe, change the 0 above to nsIClassInfo::THREADSAFE. |
michael@0 | 41 | * If it's a singleton, use nsIClassInfo::SINGLETON. The full list of flags is |
michael@0 | 42 | * in nsIClassInfo.idl. |
michael@0 | 43 | * |
michael@0 | 44 | * The nullptr parameter is there so you can pass a function for converting |
michael@0 | 45 | * from an XPCOM object to a scriptable helper. Unless you're doing |
michael@0 | 46 | * specialized JS work, you can probably leave this as nullptr. |
michael@0 | 47 | * |
michael@0 | 48 | * This file also defines the NS_IMPL_QUERY_INTERFACE_CI macro, which you can |
michael@0 | 49 | * use to replace NS_IMPL_QUERY_INTERFACE, if you use that instead of |
michael@0 | 50 | * NS_IMPL_ISUPPORTS. |
michael@0 | 51 | * |
michael@0 | 52 | * That's it! The rest is gory details. |
michael@0 | 53 | * |
michael@0 | 54 | * |
michael@0 | 55 | * Notice that nsFooBar didn't need to inherit from nsIClassInfo in order to |
michael@0 | 56 | * "implement" it. However, after adding these macros to nsFooBar, you you can |
michael@0 | 57 | * QueryInterface an instance of nsFooBar to nsIClassInfo. How can this be? |
michael@0 | 58 | * |
michael@0 | 59 | * The answer lies in the NS_IMPL_ISUPPORTS_CI macro. It modifies nsFooBar's |
michael@0 | 60 | * QueryInterface implementation such that, if we ask to QI to nsIClassInfo, it |
michael@0 | 61 | * returns a singleton object associated with the class. (That singleton is |
michael@0 | 62 | * defined by NS_IMPL_CLASSINFO.) So all nsFooBar instances will return the |
michael@0 | 63 | * same object when QI'ed to nsIClassInfo. (You can see this in |
michael@0 | 64 | * NS_IMPL_QUERY_CLASSINFO below.) |
michael@0 | 65 | * |
michael@0 | 66 | * This hack breaks XPCOM's rules, since if you take an instance of nsFooBar, |
michael@0 | 67 | * QI it to nsIClassInfo, and then try to QI to nsIFoo, that will fail. On the |
michael@0 | 68 | * upside, implementing nsIClassInfo doesn't add a vtable pointer to instances |
michael@0 | 69 | * of your class. |
michael@0 | 70 | * |
michael@0 | 71 | * In principal, you can also implement nsIClassInfo by inheriting from the |
michael@0 | 72 | * interface. But some code expects that when it QI's an object to |
michael@0 | 73 | * nsIClassInfo, it gets back a singleton which isn't attached to any |
michael@0 | 74 | * particular object. If a class were to implement nsIClassInfo through |
michael@0 | 75 | * inheritance, that code might QI to nsIClassInfo and keep the resulting |
michael@0 | 76 | * object alive, thinking it was only keeping alive the classinfo singleton, |
michael@0 | 77 | * but in fact keeping a whole instance of the class alive. See, e.g., bug |
michael@0 | 78 | * 658632. |
michael@0 | 79 | * |
michael@0 | 80 | * Unless you specifically need to have a different nsIClassInfo instance for |
michael@0 | 81 | * each instance of your class, you should probably just implement nsIClassInfo |
michael@0 | 82 | * as a singleton. |
michael@0 | 83 | */ |
michael@0 | 84 | |
michael@0 | 85 | class NS_COM_GLUE GenericClassInfo : public nsIClassInfo |
michael@0 | 86 | { |
michael@0 | 87 | public: |
michael@0 | 88 | struct ClassInfoData |
michael@0 | 89 | { |
michael@0 | 90 | typedef NS_CALLBACK(GetInterfacesProc)(uint32_t* countp, |
michael@0 | 91 | nsIID*** array); |
michael@0 | 92 | typedef NS_CALLBACK(GetLanguageHelperProc)(uint32_t language, |
michael@0 | 93 | nsISupports** helper); |
michael@0 | 94 | |
michael@0 | 95 | GetInterfacesProc getinterfaces; |
michael@0 | 96 | GetLanguageHelperProc getlanguagehelper; |
michael@0 | 97 | uint32_t flags; |
michael@0 | 98 | nsCID cid; |
michael@0 | 99 | }; |
michael@0 | 100 | |
michael@0 | 101 | NS_DECL_ISUPPORTS_INHERITED |
michael@0 | 102 | NS_DECL_NSICLASSINFO |
michael@0 | 103 | |
michael@0 | 104 | GenericClassInfo(const ClassInfoData* data) |
michael@0 | 105 | : mData(data) |
michael@0 | 106 | { } |
michael@0 | 107 | |
michael@0 | 108 | private: |
michael@0 | 109 | const ClassInfoData* mData; |
michael@0 | 110 | }; |
michael@0 | 111 | |
michael@0 | 112 | #define NS_CLASSINFO_NAME(_class) g##_class##_classInfoGlobal |
michael@0 | 113 | #define NS_CI_INTERFACE_GETTER_NAME(_class) _class##_GetInterfacesHelper |
michael@0 | 114 | #define NS_DECL_CI_INTERFACE_GETTER(_class) \ |
michael@0 | 115 | extern NS_IMETHODIMP NS_CI_INTERFACE_GETTER_NAME(_class) \ |
michael@0 | 116 | (uint32_t *, nsIID ***); |
michael@0 | 117 | |
michael@0 | 118 | #define NS_IMPL_CLASSINFO(_class, _getlanguagehelper, _flags, _cid) \ |
michael@0 | 119 | NS_DECL_CI_INTERFACE_GETTER(_class) \ |
michael@0 | 120 | static const GenericClassInfo::ClassInfoData k##_class##ClassInfoData = { \ |
michael@0 | 121 | NS_CI_INTERFACE_GETTER_NAME(_class), \ |
michael@0 | 122 | _getlanguagehelper, \ |
michael@0 | 123 | _flags | nsIClassInfo::SINGLETON_CLASSINFO, \ |
michael@0 | 124 | _cid, \ |
michael@0 | 125 | }; \ |
michael@0 | 126 | mozilla::AlignedStorage2<GenericClassInfo> k##_class##ClassInfoDataPlace; \ |
michael@0 | 127 | nsIClassInfo* NS_CLASSINFO_NAME(_class) = nullptr; |
michael@0 | 128 | |
michael@0 | 129 | #define NS_IMPL_QUERY_CLASSINFO(_class) \ |
michael@0 | 130 | if ( aIID.Equals(NS_GET_IID(nsIClassInfo)) ) { \ |
michael@0 | 131 | if (!NS_CLASSINFO_NAME(_class)) \ |
michael@0 | 132 | NS_CLASSINFO_NAME(_class) = new (k##_class##ClassInfoDataPlace.addr()) \ |
michael@0 | 133 | GenericClassInfo(&k##_class##ClassInfoData); \ |
michael@0 | 134 | foundInterface = NS_CLASSINFO_NAME(_class); \ |
michael@0 | 135 | } else |
michael@0 | 136 | |
michael@0 | 137 | #define NS_CLASSINFO_HELPER_BEGIN(_class, _c) \ |
michael@0 | 138 | NS_IMETHODIMP \ |
michael@0 | 139 | NS_CI_INTERFACE_GETTER_NAME(_class)(uint32_t *count, nsIID ***array) \ |
michael@0 | 140 | { \ |
michael@0 | 141 | *count = _c; \ |
michael@0 | 142 | *array = (nsIID **)nsMemory::Alloc(sizeof (nsIID *) * _c); \ |
michael@0 | 143 | uint32_t i = 0; |
michael@0 | 144 | |
michael@0 | 145 | #define NS_CLASSINFO_HELPER_ENTRY(_interface) \ |
michael@0 | 146 | (*array)[i++] = (nsIID*)nsMemory::Clone(&NS_GET_IID(_interface), \ |
michael@0 | 147 | sizeof(nsIID)); |
michael@0 | 148 | |
michael@0 | 149 | #define NS_CLASSINFO_HELPER_END \ |
michael@0 | 150 | MOZ_ASSERT(i == *count, "Incorrent number of entries"); \ |
michael@0 | 151 | return NS_OK; \ |
michael@0 | 152 | } |
michael@0 | 153 | |
michael@0 | 154 | #define NS_IMPL_CI_INTERFACE_GETTER(aClass, ...) \ |
michael@0 | 155 | MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__); \ |
michael@0 | 156 | NS_CLASSINFO_HELPER_BEGIN(aClass, \ |
michael@0 | 157 | MOZ_PASTE_PREFIX_AND_ARG_COUNT(/* No prefix */, \ |
michael@0 | 158 | __VA_ARGS__)) \ |
michael@0 | 159 | MOZ_FOR_EACH(NS_CLASSINFO_HELPER_ENTRY, (), (__VA_ARGS__)) \ |
michael@0 | 160 | NS_CLASSINFO_HELPER_END |
michael@0 | 161 | |
michael@0 | 162 | #define NS_IMPL_QUERY_INTERFACE_CI(aClass, ...) \ |
michael@0 | 163 | MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__); \ |
michael@0 | 164 | NS_INTERFACE_MAP_BEGIN(aClass) \ |
michael@0 | 165 | MOZ_FOR_EACH(NS_INTERFACE_MAP_ENTRY, (), (__VA_ARGS__)) \ |
michael@0 | 166 | NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, MOZ_ARG_1(__VA_ARGS__)) \ |
michael@0 | 167 | NS_IMPL_QUERY_CLASSINFO(aClass) \ |
michael@0 | 168 | NS_INTERFACE_MAP_END |
michael@0 | 169 | |
michael@0 | 170 | #define NS_IMPL_ISUPPORTS_CI(aClass, ...) \ |
michael@0 | 171 | NS_IMPL_ADDREF(aClass) \ |
michael@0 | 172 | NS_IMPL_RELEASE(aClass) \ |
michael@0 | 173 | NS_IMPL_QUERY_INTERFACE_CI(aClass, __VA_ARGS__) \ |
michael@0 | 174 | NS_IMPL_CI_INTERFACE_GETTER(aClass, __VA_ARGS__) |
michael@0 | 175 | |
michael@0 | 176 | #endif // nsIClassInfoImpl_h__ |