Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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 "js/RootingAPI.h"
17 : #include "js/Value.h"
18 :
19 : #include "mozilla/Maybe.h"
20 : #include "mozilla/RootedOwningNonNull.h"
21 : #include "mozilla/RootedRefPtr.h"
22 :
23 : #include "mozilla/dom/DOMString.h"
24 :
25 : #include "nsCOMPtr.h"
26 : #include "nsStringGlue.h"
27 : #include "nsTArray.h"
28 :
29 : class nsIPrincipal;
30 : class nsWrapperCache;
31 :
32 : namespace mozilla {
33 : namespace dom {
34 :
35 : // Struct that serves as a base class for all dictionaries. Particularly useful
36 : // so we can use IsBaseOf to detect dictionary template arguments.
37 2905 : struct DictionaryBase
38 : {
39 : protected:
40 : bool ParseJSON(JSContext* aCx, const nsAString& aJSON,
41 : JS::MutableHandle<JS::Value> aVal);
42 :
43 : bool StringifyToJSON(JSContext* aCx,
44 : JS::Handle<JSObject*> aObj,
45 : nsAString& aJSON) const;
46 :
47 : // Struct used as a way to force a dictionary constructor to not init the
48 : // dictionary (via constructing from a pointer to this class). We're putting
49 : // it here so that all the dictionaries will have access to it, but outside
50 : // code will not.
51 : struct FastDictionaryInitializer {
52 : };
53 :
54 : bool mIsAnyMemberPresent = false;
55 :
56 : private:
57 : // aString is expected to actually be an nsAString*. Should only be
58 : // called from StringifyToJSON.
59 : static bool AppendJSONToString(const char16_t* aJSONData,
60 : uint32_t aDataLength, void* aString);
61 :
62 : public:
63 2 : bool IsAnyMemberPresent() const
64 : {
65 2 : return mIsAnyMemberPresent;
66 : }
67 : };
68 :
69 : // Struct that serves as a base class for all typed arrays and array buffers and
70 : // array buffer views. Particularly useful so we can use IsBaseOf to detect
71 : // typed array/buffer/view template arguments.
72 0 : struct AllTypedArraysBase {
73 : };
74 :
75 : // Struct that serves as a base class for all owning unions.
76 : // Particularly useful so we can use IsBaseOf to detect owning union
77 : // template arguments.
78 2 : struct AllOwningUnionBase {
79 : };
80 :
81 :
82 : struct EnumEntry {
83 : const char* value;
84 : size_t length;
85 : };
86 :
87 : enum class CallerType : uint32_t;
88 :
89 19 : class MOZ_STACK_CLASS GlobalObject
90 : {
91 : public:
92 : GlobalObject(JSContext* aCx, JSObject* aObject);
93 :
94 18 : JSObject* Get() const
95 : {
96 18 : return mGlobalJSObject;
97 : }
98 :
99 : nsISupports* GetAsSupports() const;
100 :
101 : // The context that this returns is not guaranteed to be in the compartment of
102 : // the object returned from Get(), in fact it's generally in the caller's
103 : // compartment.
104 23 : JSContext* Context() const
105 : {
106 23 : return mCx;
107 : }
108 :
109 18 : bool Failed() const
110 : {
111 18 : return !Get();
112 : }
113 :
114 : // It returns the subjectPrincipal if called on the main-thread, otherwise
115 : // a nullptr is returned.
116 : nsIPrincipal* GetSubjectPrincipal() const;
117 :
118 : // Get the caller type. Note that this needs to be called before anyone has
119 : // had a chance to mess with the JSContext.
120 : dom::CallerType CallerType() const;
121 :
122 : protected:
123 : JS::Rooted<JSObject*> mGlobalJSObject;
124 : JSContext* mCx;
125 : mutable nsISupports* MOZ_UNSAFE_REF("Valid because GlobalObject is a stack "
126 : "class, and mGlobalObject points to the "
127 : "global, so it won't be destroyed as long "
128 : "as GlobalObject lives on the stack") mGlobalObject;
129 : };
130 :
131 : // Class for representing optional arguments.
132 : template<typename T, typename InternalType>
133 159 : class Optional_base
134 : {
135 : public:
136 159 : Optional_base()
137 159 : {}
138 :
139 0 : explicit Optional_base(const T& aValue)
140 0 : {
141 0 : mImpl.emplace(aValue);
142 0 : }
143 :
144 : bool operator==(const Optional_base<T, InternalType>& aOther) const
145 : {
146 : return mImpl == aOther.mImpl;
147 : }
148 :
149 : template<typename T1, typename T2>
150 : explicit Optional_base(const T1& aValue1, const T2& aValue2)
151 : {
152 : mImpl.emplace(aValue1, aValue2);
153 : }
154 :
155 88 : bool WasPassed() const
156 : {
157 88 : return mImpl.isSome();
158 : }
159 :
160 : // Return InternalType here so we can work with it usefully.
161 : template<typename... Args>
162 8 : InternalType& Construct(Args&&... aArgs)
163 : {
164 8 : mImpl.emplace(Forward<Args>(aArgs)...);
165 8 : return *mImpl;
166 : }
167 :
168 1 : void Reset()
169 : {
170 1 : mImpl.reset();
171 1 : }
172 :
173 2 : const T& Value() const
174 : {
175 2 : return *mImpl;
176 : }
177 :
178 : // Return InternalType here so we can work with it usefully.
179 10 : InternalType& Value()
180 : {
181 10 : return *mImpl;
182 : }
183 :
184 : // And an explicit way to get the InternalType even if we're const.
185 4 : const InternalType& InternalValue() const
186 : {
187 4 : return *mImpl;
188 : }
189 :
190 : // If we ever decide to add conversion operators for optional arrays
191 : // like the ones Nullable has, we'll need to ensure that Maybe<> has
192 : // the boolean before the actual data.
193 :
194 : private:
195 : // Forbid copy-construction and assignment
196 : Optional_base(const Optional_base& other) = delete;
197 : const Optional_base &operator=(const Optional_base &other) = delete;
198 :
199 : protected:
200 : Maybe<InternalType> mImpl;
201 : };
202 :
203 : template<typename T>
204 157 : class Optional : public Optional_base<T, T>
205 : {
206 : public:
207 157 : Optional() :
208 157 : Optional_base<T, T>()
209 157 : {}
210 :
211 0 : explicit Optional(const T& aValue) :
212 0 : Optional_base<T, T>(aValue)
213 0 : {}
214 : };
215 :
216 : template<typename T>
217 0 : class Optional<JS::Handle<T> > :
218 : public Optional_base<JS::Handle<T>, JS::Rooted<T> >
219 : {
220 : public:
221 0 : Optional() :
222 0 : Optional_base<JS::Handle<T>, JS::Rooted<T> >()
223 0 : {}
224 :
225 : explicit Optional(JSContext* cx) :
226 : Optional_base<JS::Handle<T>, JS::Rooted<T> >()
227 : {
228 : this->Construct(cx);
229 : }
230 :
231 : Optional(JSContext* cx, const T& aValue) :
232 : Optional_base<JS::Handle<T>, JS::Rooted<T> >(cx, aValue)
233 : {}
234 :
235 : // Override the const Value() to return the right thing so we're not
236 : // returning references to temporaries.
237 0 : JS::Handle<T> Value() const
238 : {
239 0 : return *this->mImpl;
240 : }
241 :
242 : // And we have to override the non-const one too, since we're
243 : // shadowing the one on the superclass.
244 0 : JS::Rooted<T>& Value()
245 : {
246 0 : return *this->mImpl;
247 : }
248 : };
249 :
250 : // A specialization of Optional for JSObject* to make sure that when someone
251 : // calls Construct() on it we will pre-initialized the JSObject* to nullptr so
252 : // it can be traced safely.
253 : template<>
254 0 : class Optional<JSObject*> : public Optional_base<JSObject*, JSObject*>
255 : {
256 : public:
257 0 : Optional() :
258 0 : Optional_base<JSObject*, JSObject*>()
259 0 : {}
260 :
261 : explicit Optional(JSObject* aValue) :
262 : Optional_base<JSObject*, JSObject*>(aValue)
263 : {}
264 :
265 : // Don't allow us to have an uninitialized JSObject*
266 0 : JSObject*& Construct()
267 : {
268 : // The Android compiler sucks and thinks we're trying to construct
269 : // a JSObject* from an int if we don't cast here. :(
270 : return Optional_base<JSObject*, JSObject*>::Construct(
271 0 : static_cast<JSObject*>(nullptr));
272 : }
273 :
274 : template <class T1>
275 : JSObject*& Construct(const T1& t1)
276 : {
277 : return Optional_base<JSObject*, JSObject*>::Construct(t1);
278 : }
279 : };
280 :
281 : // A specialization of Optional for JS::Value to make sure no one ever uses it.
282 : template<>
283 : class Optional<JS::Value>
284 : {
285 : private:
286 : Optional() = delete;
287 :
288 : explicit Optional(const JS::Value& aValue) = delete;
289 : };
290 :
291 : // A specialization of Optional for NonNull that lets us get a T& from Value()
292 : template<typename U> class NonNull;
293 : template<typename T>
294 0 : class Optional<NonNull<T> > : public Optional_base<T, NonNull<T> >
295 : {
296 : public:
297 : // We want our Value to actually return a non-const reference, even
298 : // if we're const. At least for things that are normally pointer
299 : // types...
300 0 : T& Value() const
301 : {
302 0 : return *this->mImpl->get();
303 : }
304 :
305 : // And we have to override the non-const one too, since we're
306 : // shadowing the one on the superclass.
307 0 : NonNull<T>& Value()
308 : {
309 0 : return *this->mImpl;
310 : }
311 : };
312 :
313 : // A specialization of Optional for OwningNonNull that lets us get a
314 : // T& from Value()
315 : template<typename T>
316 4 : class Optional<OwningNonNull<T> > : public Optional_base<T, OwningNonNull<T> >
317 : {
318 : public:
319 : // We want our Value to actually return a non-const reference, even
320 : // if we're const. At least for things that are normally pointer
321 : // types...
322 0 : T& Value() const
323 : {
324 0 : return *this->mImpl->get();
325 : }
326 :
327 : // And we have to override the non-const one too, since we're
328 : // shadowing the one on the superclass.
329 0 : OwningNonNull<T>& Value()
330 : {
331 0 : return *this->mImpl;
332 : }
333 : };
334 :
335 : // Specialization for strings.
336 : // XXXbz we can't pull in FakeString here, because it depends on internal
337 : // strings. So we just have to forward-declare it and reimplement its
338 : // ToAStringPtr.
339 :
340 : namespace binding_detail {
341 : struct FakeString;
342 : } // namespace binding_detail
343 :
344 : template<>
345 : class Optional<nsAString>
346 : {
347 : public:
348 15 : Optional() : mPassed(false) {}
349 :
350 27 : bool WasPassed() const
351 : {
352 27 : return mPassed;
353 : }
354 :
355 12 : void operator=(const nsAString* str)
356 : {
357 12 : MOZ_ASSERT(str);
358 12 : mStr = str;
359 12 : mPassed = true;
360 12 : }
361 :
362 : // If this code ever goes away, remove the comment pointing to it in the
363 : // FakeString class in BindingUtils.h.
364 0 : void operator=(const binding_detail::FakeString* str)
365 : {
366 0 : MOZ_ASSERT(str);
367 0 : mStr = reinterpret_cast<const nsString*>(str);
368 0 : mPassed = true;
369 0 : }
370 :
371 12 : const nsAString& Value() const
372 : {
373 12 : MOZ_ASSERT(WasPassed());
374 12 : return *mStr;
375 : }
376 :
377 : private:
378 : // Forbid copy-construction and assignment
379 : Optional(const Optional& other) = delete;
380 : const Optional &operator=(const Optional &other) = delete;
381 :
382 : bool mPassed;
383 : const nsAString* mStr;
384 : };
385 :
386 : template<class T>
387 : class NonNull
388 : {
389 : public:
390 117 : NonNull()
391 : #ifdef DEBUG
392 117 : : inited(false)
393 : #endif
394 117 : {}
395 :
396 : // This is no worse than get() in terms of const handling.
397 117 : operator T&() const {
398 117 : MOZ_ASSERT(inited);
399 117 : MOZ_ASSERT(ptr, "NonNull<T> was set to null");
400 117 : return *ptr;
401 : }
402 :
403 : operator T*() const {
404 : MOZ_ASSERT(inited);
405 : MOZ_ASSERT(ptr, "NonNull<T> was set to null");
406 : return ptr;
407 : }
408 :
409 117 : void operator=(T* t) {
410 117 : ptr = t;
411 117 : MOZ_ASSERT(ptr);
412 : #ifdef DEBUG
413 117 : inited = true;
414 : #endif
415 117 : }
416 :
417 : template<typename U>
418 : void operator=(U* t) {
419 : ptr = t->ToAStringPtr();
420 : MOZ_ASSERT(ptr);
421 : #ifdef DEBUG
422 : inited = true;
423 : #endif
424 : }
425 :
426 : T** Slot() {
427 : #ifdef DEBUG
428 : inited = true;
429 : #endif
430 : return &ptr;
431 : }
432 :
433 : T* Ptr() {
434 : MOZ_ASSERT(inited);
435 : MOZ_ASSERT(ptr, "NonNull<T> was set to null");
436 : return ptr;
437 : }
438 :
439 : // Make us work with smart-ptr helpers that expect a get()
440 0 : T* get() const {
441 0 : MOZ_ASSERT(inited);
442 0 : MOZ_ASSERT(ptr);
443 0 : return ptr;
444 : }
445 :
446 : protected:
447 : T* ptr;
448 : #ifdef DEBUG
449 : bool inited;
450 : #endif
451 : };
452 :
453 : // Class for representing sequences in arguments. We use a non-auto array
454 : // because that allows us to use sequences of sequences and the like. This
455 : // needs to be fallible because web content controls the length of the array,
456 : // and can easily try to create very large lengths.
457 : template<typename T>
458 2 : class Sequence : public FallibleTArray<T>
459 : {
460 : public:
461 2 : Sequence() : FallibleTArray<T>()
462 2 : {}
463 : };
464 :
465 : inline nsWrapperCache*
466 459 : GetWrapperCache(nsWrapperCache* cache)
467 : {
468 459 : return cache;
469 : }
470 :
471 : inline nsWrapperCache*
472 2286 : GetWrapperCache(void* p)
473 : {
474 2286 : return nullptr;
475 : }
476 :
477 : // Helper template for smart pointers to resolve ambiguity between
478 : // GetWrappeCache(void*) and GetWrapperCache(const ParentObject&).
479 : template <template <typename> class SmartPtr, typename T>
480 : inline nsWrapperCache*
481 0 : GetWrapperCache(const SmartPtr<T>& aObject)
482 : {
483 0 : return GetWrapperCache(aObject.get());
484 : }
485 :
486 : struct MOZ_STACK_CLASS ParentObject {
487 : template<class T>
488 400 : MOZ_IMPLICIT ParentObject(T* aObject) :
489 : mObject(aObject),
490 400 : mWrapperCache(GetWrapperCache(aObject)),
491 800 : mUseXBLScope(false)
492 400 : {}
493 :
494 : template<class T, template<typename> class SmartPtr>
495 0 : MOZ_IMPLICIT ParentObject(const SmartPtr<T>& aObject) :
496 : mObject(aObject.get()),
497 0 : mWrapperCache(GetWrapperCache(aObject.get())),
498 0 : mUseXBLScope(false)
499 0 : {}
500 :
501 0 : ParentObject(nsISupports* aObject, nsWrapperCache* aCache) :
502 : mObject(aObject),
503 : mWrapperCache(aCache),
504 0 : mUseXBLScope(false)
505 0 : {}
506 :
507 : // We don't want to make this an nsCOMPtr because of performance reasons, but
508 : // it's safe because ParentObject is a stack class.
509 : nsISupports* const MOZ_NON_OWNING_REF mObject;
510 : nsWrapperCache* const mWrapperCache;
511 : bool mUseXBLScope;
512 : };
513 :
514 : namespace binding_detail {
515 :
516 : // Class for simple sequence arguments, only used internally by codegen.
517 : template<typename T>
518 23 : class AutoSequence : public AutoTArray<T, 16>
519 : {
520 : public:
521 25 : AutoSequence() : AutoTArray<T, 16>()
522 25 : {}
523 :
524 : // Allow converting to const sequences as needed
525 17 : operator const Sequence<T>&() const {
526 17 : return *reinterpret_cast<const Sequence<T>*>(this);
527 : }
528 : };
529 :
530 : } // namespace binding_detail
531 :
532 : // Enum to represent a system or non-system caller type.
533 : enum class CallerType : uint32_t {
534 : System,
535 : NonSystem
536 : };
537 :
538 : // A class that can be passed (by value or const reference) to indicate that the
539 : // caller is always a system caller. This can be used as the type of an
540 : // argument to force only system callers to call a function.
541 : class SystemCallerGuarantee {
542 : public:
543 0 : operator CallerType() const { return CallerType::System; }
544 : };
545 :
546 : } // namespace dom
547 : } // namespace mozilla
548 :
549 : #endif // mozilla_dom_BindingDeclarations_h__
|