|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #ifndef nsAgg_h___ |
|
7 #define nsAgg_h___ |
|
8 |
|
9 #include "nsISupports.h" |
|
10 #include "nsCycleCollectionParticipant.h" |
|
11 |
|
12 |
|
13 //////////////////////////////////////////////////////////////////////////////// |
|
14 |
|
15 // Put NS_DECL_AGGREGATED or NS_DECL_CYCLE_COLLECTING_AGGREGATED in your class's |
|
16 // declaration. |
|
17 #define NS_DECL_AGGREGATED \ |
|
18 NS_DECL_ISUPPORTS \ |
|
19 NS_DECL_AGGREGATED_HELPER |
|
20 |
|
21 #define NS_DECL_CYCLE_COLLECTING_AGGREGATED \ |
|
22 NS_DECL_CYCLE_COLLECTING_ISUPPORTS \ |
|
23 NS_DECL_AGGREGATED_HELPER |
|
24 |
|
25 #define NS_DECL_AGGREGATED_HELPER \ |
|
26 public: \ |
|
27 \ |
|
28 /** \ |
|
29 * Returns the nsISupports pointer of the inner object (aka the \ |
|
30 * aggregatee). This pointer is really only useful to the outer object \ |
|
31 * (aka the aggregator), which can use it to hold on to the inner \ |
|
32 * object. Anything else wants the nsISupports pointer of the outer \ |
|
33 * object (gotten by QI'ing inner or outer to nsISupports). This method \ |
|
34 * returns a non-addrefed pointer. \ |
|
35 * @return the nsISupports pointer of the inner object \ |
|
36 */ \ |
|
37 nsISupports* InnerObject(void) { return &fAggregated; } \ |
|
38 \ |
|
39 /** \ |
|
40 * Returns true if this object is part of an aggregated object. \ |
|
41 */ \ |
|
42 bool IsPartOfAggregated(void) { return fOuter != InnerObject(); } \ |
|
43 \ |
|
44 private: \ |
|
45 \ |
|
46 /* You must implement this operation instead of the nsISupports */ \ |
|
47 /* methods. */ \ |
|
48 nsresult \ |
|
49 AggregatedQueryInterface(const nsIID& aIID, void** aInstancePtr); \ |
|
50 \ |
|
51 class Internal : public nsISupports { \ |
|
52 public: \ |
|
53 \ |
|
54 Internal() {} \ |
|
55 \ |
|
56 NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); \ |
|
57 NS_IMETHOD_(MozExternalRefCountType) AddRef(void); \ |
|
58 NS_IMETHOD_(MozExternalRefCountType) Release(void); \ |
|
59 \ |
|
60 NS_DECL_OWNINGTHREAD \ |
|
61 }; \ |
|
62 \ |
|
63 friend class Internal; \ |
|
64 \ |
|
65 nsISupports* fOuter; \ |
|
66 Internal fAggregated; \ |
|
67 \ |
|
68 public: \ |
|
69 |
|
70 #define NS_DECL_AGGREGATED_CYCLE_COLLECTION_CLASS(_class) \ |
|
71 class NS_CYCLE_COLLECTION_INNERCLASS \ |
|
72 : public nsXPCOMCycleCollectionParticipant \ |
|
73 { \ |
|
74 public: \ |
|
75 NS_IMETHOD_(void) Unlink(void *p); \ |
|
76 NS_IMETHOD Traverse(void *p, nsCycleCollectionTraversalCallback &cb); \ |
|
77 NS_IMETHOD_(void) DeleteCycleCollectable(void* p) \ |
|
78 { \ |
|
79 NS_CYCLE_COLLECTION_CLASSNAME(_class):: \ |
|
80 Downcast(static_cast<nsISupports*>(p))->DeleteCycleCollectable(); \ |
|
81 } \ |
|
82 static _class* Downcast(nsISupports* s) \ |
|
83 { \ |
|
84 return (_class*)((char*)(s) - offsetof(_class, fAggregated)); \ |
|
85 } \ |
|
86 static nsISupports* Upcast(_class *p) \ |
|
87 { \ |
|
88 return p->InnerObject(); \ |
|
89 } \ |
|
90 static nsXPCOMCycleCollectionParticipant* GetParticipant() \ |
|
91 { \ |
|
92 return &_class::NS_CYCLE_COLLECTION_INNERNAME; \ |
|
93 } \ |
|
94 }; \ |
|
95 NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL(_class); \ |
|
96 static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME; |
|
97 |
|
98 // Put this in your class's constructor: |
|
99 #define NS_INIT_AGGREGATED(outer) \ |
|
100 PR_BEGIN_MACRO \ |
|
101 fOuter = outer ? outer : &fAggregated; \ |
|
102 PR_END_MACRO |
|
103 |
|
104 |
|
105 // Put this in your class's implementation file: |
|
106 #define NS_IMPL_AGGREGATED(_class) \ |
|
107 \ |
|
108 NS_IMPL_AGGREGATED_HELPER(_class) \ |
|
109 \ |
|
110 NS_IMETHODIMP_(MozExternalRefCountType) \ |
|
111 _class::Internal::AddRef(void) \ |
|
112 { \ |
|
113 _class* agg = (_class*)((char*)(this) - offsetof(_class, fAggregated)); \ |
|
114 MOZ_ASSERT(int32_t(agg->mRefCnt) >= 0, "illegal refcnt"); \ |
|
115 NS_ASSERT_OWNINGTHREAD(_class); \ |
|
116 ++agg->mRefCnt; \ |
|
117 NS_LOG_ADDREF(this, agg->mRefCnt, #_class, sizeof(*this)); \ |
|
118 return agg->mRefCnt; \ |
|
119 } \ |
|
120 \ |
|
121 NS_IMETHODIMP_(MozExternalRefCountType) \ |
|
122 _class::Internal::Release(void) \ |
|
123 { \ |
|
124 _class* agg = (_class*)((char*)(this) - offsetof(_class, fAggregated)); \ |
|
125 MOZ_ASSERT(int32_t(agg->mRefCnt) > 0, "dup release"); \ |
|
126 NS_ASSERT_OWNINGTHREAD(_class); \ |
|
127 --agg->mRefCnt; \ |
|
128 NS_LOG_RELEASE(this, agg->mRefCnt, #_class); \ |
|
129 if (agg->mRefCnt == 0) { \ |
|
130 agg->mRefCnt = 1; /* stabilize */ \ |
|
131 delete agg; \ |
|
132 return 0; \ |
|
133 } \ |
|
134 return agg->mRefCnt; \ |
|
135 } \ |
|
136 |
|
137 #define NS_IMPL_CYCLE_COLLECTING_AGGREGATED(_class) \ |
|
138 \ |
|
139 NS_IMPL_AGGREGATED_HELPER(_class) \ |
|
140 \ |
|
141 NS_IMETHODIMP_(MozExternalRefCountType) \ |
|
142 _class::Internal::AddRef(void) \ |
|
143 { \ |
|
144 _class* agg = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Downcast(this); \ |
|
145 MOZ_ASSERT(int32_t(agg->mRefCnt) >= 0, "illegal refcnt"); \ |
|
146 NS_ASSERT_OWNINGTHREAD_AGGREGATE(agg, _class); \ |
|
147 nsrefcnt count = agg->mRefCnt.incr(this); \ |
|
148 NS_LOG_ADDREF(this, count, #_class, sizeof(*agg)); \ |
|
149 return count; \ |
|
150 } \ |
|
151 NS_IMETHODIMP_(MozExternalRefCountType) \ |
|
152 _class::Internal::Release(void) \ |
|
153 { \ |
|
154 _class* agg = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Downcast(this); \ |
|
155 MOZ_ASSERT(int32_t(agg->mRefCnt) > 0, "dup release"); \ |
|
156 NS_ASSERT_OWNINGTHREAD_AGGREGATE(agg, _class); \ |
|
157 nsrefcnt count = agg->mRefCnt.decr(this); \ |
|
158 NS_LOG_RELEASE(this, count, #_class); \ |
|
159 return count; \ |
|
160 } \ |
|
161 NS_IMETHODIMP_(void) \ |
|
162 _class::DeleteCycleCollectable(void) \ |
|
163 { \ |
|
164 delete this; \ |
|
165 } |
|
166 |
|
167 #define NS_IMPL_AGGREGATED_HELPER(_class) \ |
|
168 NS_IMETHODIMP \ |
|
169 _class::QueryInterface(const nsIID& aIID, void** aInstancePtr) \ |
|
170 { \ |
|
171 return fOuter->QueryInterface(aIID, aInstancePtr); \ |
|
172 } \ |
|
173 \ |
|
174 NS_IMETHODIMP_(MozExternalRefCountType) \ |
|
175 _class::AddRef(void) \ |
|
176 { \ |
|
177 return fOuter->AddRef(); \ |
|
178 } \ |
|
179 \ |
|
180 NS_IMETHODIMP_(MozExternalRefCountType) \ |
|
181 _class::Release(void) \ |
|
182 { \ |
|
183 return fOuter->Release(); \ |
|
184 } \ |
|
185 \ |
|
186 NS_IMETHODIMP \ |
|
187 _class::Internal::QueryInterface(const nsIID& aIID, void** aInstancePtr) \ |
|
188 { \ |
|
189 _class* agg = (_class*)((char*)(this) - offsetof(_class, fAggregated)); \ |
|
190 return agg->AggregatedQueryInterface(aIID, aInstancePtr); \ |
|
191 } \ |
|
192 |
|
193 /** |
|
194 * To make aggregated objects participate in cycle collection we need to enable |
|
195 * the outer object (aggregator) to traverse/unlink the objects held by the |
|
196 * inner object (the aggregatee). We can't just make the inner object QI'able to |
|
197 * NS_CYCLECOLLECTIONPARTICIPANT_IID, we don't want to return the inner object's |
|
198 * nsCycleCollectionParticipant for the outer object (which will happen if the |
|
199 * outer object doesn't participate in cycle collection itself). |
|
200 * NS_AGGREGATED_CYCLECOLLECTIONPARTICIPANT_IID enables the outer object to get |
|
201 * the inner objects nsCycleCollectionParticipant. |
|
202 * |
|
203 * There are three cases: |
|
204 * - No aggregation |
|
205 * QI'ing to NS_CYCLECOLLECTIONPARTICIPANT_IID will return the inner |
|
206 * object's nsCycleCollectionParticipant. |
|
207 * |
|
208 * - Aggregation and outer object does not participate in cycle collection |
|
209 * QI'ing to NS_CYCLECOLLECTIONPARTICIPANT_IID will not return anything. |
|
210 * |
|
211 * - Aggregation and outer object does participate in cycle collection |
|
212 * QI'ing to NS_CYCLECOLLECTIONPARTICIPANT_IID will return the outer |
|
213 * object's nsCycleCollectionParticipant. The outer object's |
|
214 * nsCycleCollectionParticipant can then QI the inner object to |
|
215 * NS_AGGREGATED_CYCLECOLLECTIONPARTICIPANT_IID to get the inner object's |
|
216 * nsCycleCollectionParticipant, which it can use to traverse/unlink the |
|
217 * objects reachable from the inner object. |
|
218 */ |
|
219 #define NS_AGGREGATED_CYCLECOLLECTIONPARTICIPANT_IID \ |
|
220 { \ |
|
221 0x32889b7e, \ |
|
222 0xe4fe, \ |
|
223 0x43f4, \ |
|
224 { 0x85, 0x31, 0xb5, 0x28, 0x23, 0xa2, 0xe9, 0xfc } \ |
|
225 } |
|
226 |
|
227 /** |
|
228 * Just holds the IID so NS_GET_IID works. |
|
229 */ |
|
230 class nsAggregatedCycleCollectionParticipant |
|
231 { |
|
232 public: |
|
233 NS_DECLARE_STATIC_IID_ACCESSOR(NS_AGGREGATED_CYCLECOLLECTIONPARTICIPANT_IID) |
|
234 }; |
|
235 |
|
236 NS_DEFINE_STATIC_IID_ACCESSOR(nsAggregatedCycleCollectionParticipant, |
|
237 NS_AGGREGATED_CYCLECOLLECTIONPARTICIPANT_IID) |
|
238 |
|
239 // for use with QI macros in nsISupportsUtils.h: |
|
240 |
|
241 #define NS_INTERFACE_MAP_BEGIN_AGGREGATED(_class) \ |
|
242 NS_IMPL_AGGREGATED_QUERY_HEAD(_class) |
|
243 |
|
244 #define NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION_AGGREGATED(_class) \ |
|
245 NS_IMPL_QUERY_CYCLE_COLLECTION(_class) |
|
246 |
|
247 #define NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION_AGGREGATED(_class) \ |
|
248 NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION_AGGREGATED(_class) \ |
|
249 NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION_ISUPPORTS(_class) |
|
250 |
|
251 #define NS_IMPL_AGGREGATED_QUERY_HEAD(_class) \ |
|
252 nsresult \ |
|
253 _class::AggregatedQueryInterface(REFNSIID aIID, void** aInstancePtr) \ |
|
254 { \ |
|
255 NS_ASSERTION(aInstancePtr, \ |
|
256 "AggregatedQueryInterface requires a non-NULL result ptr!"); \ |
|
257 if ( !aInstancePtr ) \ |
|
258 return NS_ERROR_NULL_POINTER; \ |
|
259 nsISupports* foundInterface; \ |
|
260 if ( aIID.Equals(NS_GET_IID(nsISupports)) ) \ |
|
261 foundInterface = InnerObject(); \ |
|
262 else |
|
263 |
|
264 #define NS_IMPL_AGGREGATED_QUERY_CYCLE_COLLECTION(_class) \ |
|
265 if (aIID.Equals(IsPartOfAggregated() ? \ |
|
266 NS_GET_IID(nsCycleCollectionParticipant) : \ |
|
267 NS_GET_IID(nsAggregatedCycleCollectionParticipant))) \ |
|
268 foundInterface = NS_CYCLE_COLLECTION_PARTICIPANT(_class); \ |
|
269 else |
|
270 |
|
271 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_AGGREGATED(_class) \ |
|
272 NS_IMETHODIMP \ |
|
273 NS_CYCLE_COLLECTION_CLASSNAME(_class)::Traverse \ |
|
274 (void *p, nsCycleCollectionTraversalCallback &cb) \ |
|
275 { \ |
|
276 nsISupports *s = static_cast<nsISupports*>(p); \ |
|
277 MOZ_ASSERT(CheckForRightISupports(s), \ |
|
278 "not the nsISupports pointer we expect"); \ |
|
279 _class *tmp = static_cast<_class*>(Downcast(s)); \ |
|
280 if (!tmp->IsPartOfAggregated()) \ |
|
281 NS_IMPL_CYCLE_COLLECTION_DESCRIBE(_class, tmp->mRefCnt.get()) |
|
282 |
|
283 #define NS_GENERIC_AGGREGATED_CONSTRUCTOR(_InstanceClass) \ |
|
284 static nsresult \ |
|
285 _InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, \ |
|
286 void **aResult) \ |
|
287 { \ |
|
288 *aResult = nullptr; \ |
|
289 if (NS_WARN_IF(aOuter && !aIID.Equals(NS_GET_IID(nsISupports)))) \ |
|
290 return NS_ERROR_INVALID_ARG; \ |
|
291 \ |
|
292 _InstanceClass* inst = new _InstanceClass(aOuter); \ |
|
293 if (!inst) { \ |
|
294 return NS_ERROR_OUT_OF_MEMORY; \ |
|
295 } \ |
|
296 \ |
|
297 nsISupports* inner = inst->InnerObject(); \ |
|
298 nsresult rv = inner->QueryInterface(aIID, aResult); \ |
|
299 if (NS_FAILED(rv)) { \ |
|
300 delete inst; \ |
|
301 } \ |
|
302 \ |
|
303 return rv; \ |
|
304 } \ |
|
305 |
|
306 #define NS_GENERIC_AGGREGATED_CONSTRUCTOR_INIT(_InstanceClass, _InitMethod) \ |
|
307 static nsresult \ |
|
308 _InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, \ |
|
309 void **aResult) \ |
|
310 { \ |
|
311 *aResult = nullptr; \ |
|
312 if (NS_WARN_IF(aOuter && !aIID.Equals(NS_GET_IID(nsISupports)))) \ |
|
313 return NS_ERROR_INVALID_ARG; \ |
|
314 \ |
|
315 _InstanceClass* inst = new _InstanceClass(aOuter); \ |
|
316 if (!inst) { \ |
|
317 return NS_ERROR_OUT_OF_MEMORY; \ |
|
318 } \ |
|
319 \ |
|
320 nsISupports* inner = inst->InnerObject(); \ |
|
321 NS_ADDREF(inner); \ |
|
322 nsresult rv = inst->_InitMethod(); \ |
|
323 if (NS_SUCCEEDED(rv)) { \ |
|
324 rv = inner->QueryInterface(aIID, aResult); \ |
|
325 } \ |
|
326 NS_RELEASE(inner); \ |
|
327 \ |
|
328 return rv; \ |
|
329 } \ |
|
330 |
|
331 #endif /* nsAgg_h___ */ |