|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ |
|
2 /* vim: set ts=2 sw=2 et tw=79: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 /** |
|
8 * A header for declaring various things that binding implementation headers |
|
9 * might need. The idea is to make binding implementation headers safe to |
|
10 * include anywhere without running into include hell like we do with |
|
11 * BindingUtils.h |
|
12 */ |
|
13 #ifndef mozilla_dom_BindingDeclarations_h__ |
|
14 #define mozilla_dom_BindingDeclarations_h__ |
|
15 |
|
16 #include "nsStringGlue.h" |
|
17 #include "js/Value.h" |
|
18 #include "js/RootingAPI.h" |
|
19 #include "mozilla/Maybe.h" |
|
20 #include "nsCOMPtr.h" |
|
21 #include "nsTArray.h" |
|
22 #include "nsAutoPtr.h" // for nsRefPtr member variables |
|
23 #include "mozilla/dom/DOMString.h" |
|
24 #include "mozilla/dom/OwningNonNull.h" |
|
25 |
|
26 class nsWrapperCache; |
|
27 |
|
28 namespace mozilla { |
|
29 namespace dom { |
|
30 |
|
31 // Struct that serves as a base class for all dictionaries. Particularly useful |
|
32 // so we can use IsBaseOf to detect dictionary template arguments. |
|
33 struct DictionaryBase |
|
34 { |
|
35 protected: |
|
36 bool ParseJSON(JSContext* aCx, const nsAString& aJSON, |
|
37 JS::MutableHandle<JS::Value> aVal); |
|
38 }; |
|
39 |
|
40 // Struct that serves as a base class for all typed arrays and array buffers and |
|
41 // array buffer views. Particularly useful so we can use IsBaseOf to detect |
|
42 // typed array/buffer/view template arguments. |
|
43 struct AllTypedArraysBase { |
|
44 }; |
|
45 |
|
46 // Struct that serves as a base class for all owning unions. |
|
47 // Particularly useful so we can use IsBaseOf to detect owning union |
|
48 // template arguments. |
|
49 struct AllOwningUnionBase { |
|
50 }; |
|
51 |
|
52 |
|
53 struct EnumEntry { |
|
54 const char* value; |
|
55 size_t length; |
|
56 }; |
|
57 |
|
58 class MOZ_STACK_CLASS GlobalObject |
|
59 { |
|
60 public: |
|
61 GlobalObject(JSContext* aCx, JSObject* aObject); |
|
62 |
|
63 JSObject* Get() const |
|
64 { |
|
65 return mGlobalJSObject; |
|
66 } |
|
67 |
|
68 nsISupports* GetAsSupports() const; |
|
69 |
|
70 // The context that this returns is not guaranteed to be in the compartment of |
|
71 // the object returned from Get(), in fact it's generally in the caller's |
|
72 // compartment. |
|
73 JSContext* GetContext() const |
|
74 { |
|
75 return mCx; |
|
76 } |
|
77 |
|
78 bool Failed() const |
|
79 { |
|
80 return !Get(); |
|
81 } |
|
82 |
|
83 protected: |
|
84 JS::Rooted<JSObject*> mGlobalJSObject; |
|
85 JSContext* mCx; |
|
86 mutable nsISupports* mGlobalObject; |
|
87 mutable nsCOMPtr<nsISupports> mGlobalObjectRef; |
|
88 }; |
|
89 |
|
90 // Class for representing optional arguments. |
|
91 template<typename T, typename InternalType> |
|
92 class Optional_base |
|
93 { |
|
94 public: |
|
95 Optional_base() |
|
96 {} |
|
97 |
|
98 explicit Optional_base(const T& aValue) |
|
99 { |
|
100 mImpl.construct(aValue); |
|
101 } |
|
102 |
|
103 template<typename T1, typename T2> |
|
104 explicit Optional_base(const T1& aValue1, const T2& aValue2) |
|
105 { |
|
106 mImpl.construct(aValue1, aValue2); |
|
107 } |
|
108 |
|
109 bool WasPassed() const |
|
110 { |
|
111 return !mImpl.empty(); |
|
112 } |
|
113 |
|
114 // Return InternalType here so we can work with it usefully. |
|
115 InternalType& Construct() |
|
116 { |
|
117 mImpl.construct(); |
|
118 return mImpl.ref(); |
|
119 } |
|
120 |
|
121 template <class T1> |
|
122 InternalType& Construct(const T1 &t1) |
|
123 { |
|
124 mImpl.construct(t1); |
|
125 return mImpl.ref(); |
|
126 } |
|
127 |
|
128 template <class T1, class T2> |
|
129 InternalType& Construct(const T1 &t1, const T2 &t2) |
|
130 { |
|
131 mImpl.construct(t1, t2); |
|
132 return mImpl.ref(); |
|
133 } |
|
134 |
|
135 void Reset() |
|
136 { |
|
137 if (WasPassed()) { |
|
138 mImpl.destroy(); |
|
139 } |
|
140 } |
|
141 |
|
142 const T& Value() const |
|
143 { |
|
144 return mImpl.ref(); |
|
145 } |
|
146 |
|
147 // Return InternalType here so we can work with it usefully. |
|
148 InternalType& Value() |
|
149 { |
|
150 return mImpl.ref(); |
|
151 } |
|
152 |
|
153 // And an explicit way to get the InternalType even if we're const. |
|
154 const InternalType& InternalValue() const |
|
155 { |
|
156 return mImpl.ref(); |
|
157 } |
|
158 |
|
159 // If we ever decide to add conversion operators for optional arrays |
|
160 // like the ones Nullable has, we'll need to ensure that Maybe<> has |
|
161 // the boolean before the actual data. |
|
162 |
|
163 private: |
|
164 // Forbid copy-construction and assignment |
|
165 Optional_base(const Optional_base& other) MOZ_DELETE; |
|
166 const Optional_base &operator=(const Optional_base &other) MOZ_DELETE; |
|
167 |
|
168 protected: |
|
169 Maybe<InternalType> mImpl; |
|
170 }; |
|
171 |
|
172 template<typename T> |
|
173 class Optional : public Optional_base<T, T> |
|
174 { |
|
175 public: |
|
176 Optional() : |
|
177 Optional_base<T, T>() |
|
178 {} |
|
179 |
|
180 explicit Optional(const T& aValue) : |
|
181 Optional_base<T, T>(aValue) |
|
182 {} |
|
183 }; |
|
184 |
|
185 template<typename T> |
|
186 class Optional<JS::Handle<T> > : |
|
187 public Optional_base<JS::Handle<T>, JS::Rooted<T> > |
|
188 { |
|
189 public: |
|
190 Optional() : |
|
191 Optional_base<JS::Handle<T>, JS::Rooted<T> >() |
|
192 {} |
|
193 |
|
194 Optional(JSContext* cx) : |
|
195 Optional_base<JS::Handle<T>, JS::Rooted<T> >() |
|
196 { |
|
197 this->Construct(cx); |
|
198 } |
|
199 |
|
200 Optional(JSContext* cx, const T& aValue) : |
|
201 Optional_base<JS::Handle<T>, JS::Rooted<T> >(cx, aValue) |
|
202 {} |
|
203 |
|
204 // Override the const Value() to return the right thing so we're not |
|
205 // returning references to temporaries. |
|
206 JS::Handle<T> Value() const |
|
207 { |
|
208 return this->mImpl.ref(); |
|
209 } |
|
210 |
|
211 // And we have to override the non-const one too, since we're |
|
212 // shadowing the one on the superclass. |
|
213 JS::Rooted<T>& Value() |
|
214 { |
|
215 return this->mImpl.ref(); |
|
216 } |
|
217 }; |
|
218 |
|
219 // A specialization of Optional for JSObject* to make sure that when someone |
|
220 // calls Construct() on it we will pre-initialized the JSObject* to nullptr so |
|
221 // it can be traced safely. |
|
222 template<> |
|
223 class Optional<JSObject*> : public Optional_base<JSObject*, JSObject*> |
|
224 { |
|
225 public: |
|
226 Optional() : |
|
227 Optional_base<JSObject*, JSObject*>() |
|
228 {} |
|
229 |
|
230 explicit Optional(JSObject* aValue) : |
|
231 Optional_base<JSObject*, JSObject*>(aValue) |
|
232 {} |
|
233 |
|
234 // Don't allow us to have an uninitialized JSObject* |
|
235 JSObject*& Construct() |
|
236 { |
|
237 // The Android compiler sucks and thinks we're trying to construct |
|
238 // a JSObject* from an int if we don't cast here. :( |
|
239 return Optional_base<JSObject*, JSObject*>::Construct( |
|
240 static_cast<JSObject*>(nullptr)); |
|
241 } |
|
242 |
|
243 template <class T1> |
|
244 JSObject*& Construct(const T1& t1) |
|
245 { |
|
246 return Optional_base<JSObject*, JSObject*>::Construct(t1); |
|
247 } |
|
248 }; |
|
249 |
|
250 // A specialization of Optional for JS::Value to make sure no one ever uses it. |
|
251 template<> |
|
252 class Optional<JS::Value> |
|
253 { |
|
254 private: |
|
255 Optional() MOZ_DELETE; |
|
256 |
|
257 explicit Optional(JS::Value aValue) MOZ_DELETE; |
|
258 }; |
|
259 |
|
260 // A specialization of Optional for NonNull that lets us get a T& from Value() |
|
261 template<typename U> class NonNull; |
|
262 template<typename T> |
|
263 class Optional<NonNull<T> > : public Optional_base<T, NonNull<T> > |
|
264 { |
|
265 public: |
|
266 // We want our Value to actually return a non-const reference, even |
|
267 // if we're const. At least for things that are normally pointer |
|
268 // types... |
|
269 T& Value() const |
|
270 { |
|
271 return *this->mImpl.ref().get(); |
|
272 } |
|
273 |
|
274 // And we have to override the non-const one too, since we're |
|
275 // shadowing the one on the superclass. |
|
276 NonNull<T>& Value() |
|
277 { |
|
278 return this->mImpl.ref(); |
|
279 } |
|
280 }; |
|
281 |
|
282 // A specialization of Optional for OwningNonNull that lets us get a |
|
283 // T& from Value() |
|
284 template<typename T> |
|
285 class Optional<OwningNonNull<T> > : public Optional_base<T, OwningNonNull<T> > |
|
286 { |
|
287 public: |
|
288 // We want our Value to actually return a non-const reference, even |
|
289 // if we're const. At least for things that are normally pointer |
|
290 // types... |
|
291 T& Value() const |
|
292 { |
|
293 return *this->mImpl.ref().get(); |
|
294 } |
|
295 |
|
296 // And we have to override the non-const one too, since we're |
|
297 // shadowing the one on the superclass. |
|
298 OwningNonNull<T>& Value() |
|
299 { |
|
300 return this->mImpl.ref(); |
|
301 } |
|
302 }; |
|
303 |
|
304 // Specialization for strings. |
|
305 // XXXbz we can't pull in FakeDependentString here, because it depends on |
|
306 // internal strings. So we just have to forward-declare it and reimplement its |
|
307 // ToAStringPtr. |
|
308 |
|
309 namespace binding_detail { |
|
310 struct FakeDependentString; |
|
311 } // namespace binding_detail |
|
312 |
|
313 template<> |
|
314 class Optional<nsAString> |
|
315 { |
|
316 public: |
|
317 Optional() : mPassed(false) {} |
|
318 |
|
319 bool WasPassed() const |
|
320 { |
|
321 return mPassed; |
|
322 } |
|
323 |
|
324 void operator=(const nsAString* str) |
|
325 { |
|
326 MOZ_ASSERT(str); |
|
327 mStr = str; |
|
328 mPassed = true; |
|
329 } |
|
330 |
|
331 // If this code ever goes away, remove the comment pointing to it in the |
|
332 // FakeDependentString class in BindingUtils.h. |
|
333 void operator=(const binding_detail::FakeDependentString* str) |
|
334 { |
|
335 MOZ_ASSERT(str); |
|
336 mStr = reinterpret_cast<const nsDependentString*>(str); |
|
337 mPassed = true; |
|
338 } |
|
339 |
|
340 const nsAString& Value() const |
|
341 { |
|
342 MOZ_ASSERT(WasPassed()); |
|
343 return *mStr; |
|
344 } |
|
345 |
|
346 private: |
|
347 // Forbid copy-construction and assignment |
|
348 Optional(const Optional& other) MOZ_DELETE; |
|
349 const Optional &operator=(const Optional &other) MOZ_DELETE; |
|
350 |
|
351 bool mPassed; |
|
352 const nsAString* mStr; |
|
353 }; |
|
354 |
|
355 template<class T> |
|
356 class NonNull |
|
357 { |
|
358 public: |
|
359 NonNull() |
|
360 #ifdef DEBUG |
|
361 : inited(false) |
|
362 #endif |
|
363 {} |
|
364 |
|
365 operator T&() { |
|
366 MOZ_ASSERT(inited); |
|
367 MOZ_ASSERT(ptr, "NonNull<T> was set to null"); |
|
368 return *ptr; |
|
369 } |
|
370 |
|
371 operator const T&() const { |
|
372 MOZ_ASSERT(inited); |
|
373 MOZ_ASSERT(ptr, "NonNull<T> was set to null"); |
|
374 return *ptr; |
|
375 } |
|
376 |
|
377 operator T*() { |
|
378 MOZ_ASSERT(inited); |
|
379 MOZ_ASSERT(ptr, "NonNull<T> was set to null"); |
|
380 return ptr; |
|
381 } |
|
382 |
|
383 void operator=(T* t) { |
|
384 ptr = t; |
|
385 MOZ_ASSERT(ptr); |
|
386 #ifdef DEBUG |
|
387 inited = true; |
|
388 #endif |
|
389 } |
|
390 |
|
391 template<typename U> |
|
392 void operator=(U* t) { |
|
393 ptr = t->ToAStringPtr(); |
|
394 MOZ_ASSERT(ptr); |
|
395 #ifdef DEBUG |
|
396 inited = true; |
|
397 #endif |
|
398 } |
|
399 |
|
400 T** Slot() { |
|
401 #ifdef DEBUG |
|
402 inited = true; |
|
403 #endif |
|
404 return &ptr; |
|
405 } |
|
406 |
|
407 T* Ptr() { |
|
408 MOZ_ASSERT(inited); |
|
409 MOZ_ASSERT(ptr, "NonNull<T> was set to null"); |
|
410 return ptr; |
|
411 } |
|
412 |
|
413 // Make us work with smart-ptr helpers that expect a get() |
|
414 T* get() const { |
|
415 MOZ_ASSERT(inited); |
|
416 MOZ_ASSERT(ptr); |
|
417 return ptr; |
|
418 } |
|
419 |
|
420 protected: |
|
421 T* ptr; |
|
422 #ifdef DEBUG |
|
423 bool inited; |
|
424 #endif |
|
425 }; |
|
426 |
|
427 // Class for representing sequences in arguments. We use a non-auto array |
|
428 // because that allows us to use sequences of sequences and the like. This |
|
429 // needs to be fallible because web content controls the length of the array, |
|
430 // and can easily try to create very large lengths. |
|
431 template<typename T> |
|
432 class Sequence : public FallibleTArray<T> |
|
433 { |
|
434 public: |
|
435 Sequence() : FallibleTArray<T>() |
|
436 {} |
|
437 }; |
|
438 |
|
439 inline nsWrapperCache* |
|
440 GetWrapperCache(nsWrapperCache* cache) |
|
441 { |
|
442 return cache; |
|
443 } |
|
444 |
|
445 inline nsWrapperCache* |
|
446 GetWrapperCache(void* p) |
|
447 { |
|
448 return nullptr; |
|
449 } |
|
450 |
|
451 // Helper template for smart pointers to resolve ambiguity between |
|
452 // GetWrappeCache(void*) and GetWrapperCache(const ParentObject&). |
|
453 template <template <typename> class SmartPtr, typename T> |
|
454 inline nsWrapperCache* |
|
455 GetWrapperCache(const SmartPtr<T>& aObject) |
|
456 { |
|
457 return GetWrapperCache(aObject.get()); |
|
458 } |
|
459 |
|
460 struct ParentObject { |
|
461 template<class T> |
|
462 ParentObject(T* aObject) : |
|
463 mObject(aObject), |
|
464 mWrapperCache(GetWrapperCache(aObject)), |
|
465 mUseXBLScope(false) |
|
466 {} |
|
467 |
|
468 template<class T, template<typename> class SmartPtr> |
|
469 ParentObject(const SmartPtr<T>& aObject) : |
|
470 mObject(aObject.get()), |
|
471 mWrapperCache(GetWrapperCache(aObject.get())), |
|
472 mUseXBLScope(false) |
|
473 {} |
|
474 |
|
475 ParentObject(nsISupports* aObject, nsWrapperCache* aCache) : |
|
476 mObject(aObject), |
|
477 mWrapperCache(aCache), |
|
478 mUseXBLScope(false) |
|
479 {} |
|
480 |
|
481 nsISupports* const mObject; |
|
482 nsWrapperCache* const mWrapperCache; |
|
483 bool mUseXBLScope; |
|
484 }; |
|
485 |
|
486 } // namespace dom |
|
487 } // namespace mozilla |
|
488 |
|
489 #endif // mozilla_dom_BindingDeclarations_h__ |