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