xpcom/glue/nsIClassInfoImpl.h

branch
TOR_BUG_9701
changeset 8
97036ab72558
equal deleted inserted replaced
-1:000000000000 0:798921dd3b87
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__

mercurial