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/. */
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
13 #ifndef mozilla_dom_BindingDeclarations_h__
14 #define mozilla_dom_BindingDeclarations_h__
16 #include "js/RootingAPI.h"
17 #include "js/TypeDecls.h"
19 #include "mozilla/Maybe.h"
21 #include "mozilla/dom/DOMString.h"
27 #include <type_traits>
30 #include "mozilla/RootedOwningNonNull.h"
31 #include "mozilla/RootedRefPtr.h"
40 class CopyableErrorResult
;
44 class BindingCallContext
;
46 // Struct that serves as a base class for all dictionaries. Particularly useful
47 // so we can use std::is_base_of to detect dictionary template arguments.
48 struct DictionaryBase
{
50 bool ParseJSON(JSContext
* aCx
, const nsAString
& aJSON
,
51 JS::MutableHandle
<JS::Value
> aVal
);
53 bool StringifyToJSON(JSContext
* aCx
, JS::Handle
<JSObject
*> aObj
,
54 nsAString
& aJSON
) const;
56 // Struct used as a way to force a dictionary constructor to not init the
57 // dictionary (via constructing from a pointer to this class). We're putting
58 // it here so that all the dictionaries will have access to it, but outside
60 struct FastDictionaryInitializer
{};
62 bool mIsAnyMemberPresent
= false;
65 // aString is expected to actually be an nsAString*. Should only be
66 // called from StringifyToJSON.
67 static bool AppendJSONToString(const char16_t
* aJSONData
,
68 uint32_t aDataLength
, void* aString
);
71 bool IsAnyMemberPresent() const { return mIsAnyMemberPresent
; }
75 constexpr bool is_dom_dictionary
= std::is_base_of_v
<DictionaryBase
, T
>;
78 inline std::enable_if_t
<is_dom_dictionary
<T
>, void> ImplCycleCollectionUnlink(
80 aDictionary
.UnlinkForCC();
84 inline std::enable_if_t
<is_dom_dictionary
<T
>, void> ImplCycleCollectionTraverse(
85 nsCycleCollectionTraversalCallback
& aCallback
, T
& aDictionary
,
86 const char* aName
, uint32_t aFlags
= 0) {
87 aDictionary
.TraverseForCC(aCallback
, aFlags
);
91 inline std::enable_if_t
<is_dom_dictionary
<T
>, void> ImplCycleCollectionUnlink(
92 UniquePtr
<T
>& aDictionary
) {
97 inline std::enable_if_t
<is_dom_dictionary
<T
>, void> ImplCycleCollectionTraverse(
98 nsCycleCollectionTraversalCallback
& aCallback
, UniquePtr
<T
>& aDictionary
,
99 const char* aName
, uint32_t aFlags
= 0) {
101 ImplCycleCollectionTraverse(aCallback
, *aDictionary
, aName
, aFlags
);
104 // Struct that serves as a base class for all typed arrays and array buffers and
105 // array buffer views. Particularly useful so we can use std::is_base_of to
106 // detect typed array/buffer/view template arguments.
107 struct AllTypedArraysBase
{};
110 constexpr bool is_dom_typed_array
= std::is_base_of_v
<AllTypedArraysBase
, T
>;
112 // Struct that serves as a base class for all unions.
113 // Particularly useful so we can use std::is_base_of to detect union
114 // template arguments.
115 struct AllUnionBase
{};
118 constexpr bool is_dom_union
= std::is_base_of_v
<AllUnionBase
, T
>;
120 // Struct that serves as a base class for all owning unions.
121 // Particularly useful so we can use std::is_base_of to detect owning union
122 // template arguments.
123 struct AllOwningUnionBase
: public AllUnionBase
{};
126 constexpr bool is_dom_owning_union
= std::is_base_of_v
<AllOwningUnionBase
, T
>;
128 struct UnionWithTypedArraysBase
{};
131 constexpr bool is_dom_union_with_typedarray_members
=
132 std::is_base_of_v
<UnionWithTypedArraysBase
, T
>;
139 enum class CallerType
: uint32_t;
141 class MOZ_STACK_CLASS GlobalObject
{
143 GlobalObject(JSContext
* aCx
, JSObject
* aObject
);
145 JSObject
* Get() const { return mGlobalJSObject
; }
147 nsISupports
* GetAsSupports() const;
149 // The context that this returns is not guaranteed to be in the compartment of
150 // the object returned from Get(), in fact it's generally in the caller's
152 JSContext
* Context() const { return mCx
; }
154 bool Failed() const { return !Get(); }
156 // It returns the subjectPrincipal if called on the main-thread, otherwise
157 // a nullptr is returned.
158 nsIPrincipal
* GetSubjectPrincipal() const;
160 // Get the caller type. Note that this needs to be called before anyone has
161 // had a chance to mess with the JSContext.
162 dom::CallerType
CallerType() const;
165 JS::Rooted
<JSObject
*> mGlobalJSObject
;
167 mutable nsISupports
* MOZ_UNSAFE_REF(
168 "Valid because GlobalObject is a stack "
169 "class, and mGlobalObject points to the "
170 "global, so it won't be destroyed as long "
171 "as GlobalObject lives on the stack") mGlobalObject
;
174 // Class for representing optional arguments.
175 template <typename T
, typename InternalType
>
176 class Optional_base
{
178 Optional_base() = default;
180 Optional_base(Optional_base
&&) = default;
181 Optional_base
& operator=(Optional_base
&&) = default;
183 explicit Optional_base(const T
& aValue
) { mImpl
.emplace(aValue
); }
184 explicit Optional_base(T
&& aValue
) { mImpl
.emplace(std::move(aValue
)); }
186 bool operator==(const Optional_base
<T
, InternalType
>& aOther
) const {
187 return mImpl
== aOther
.mImpl
;
190 bool operator!=(const Optional_base
<T
, InternalType
>& aOther
) const {
191 return mImpl
!= aOther
.mImpl
;
194 template <typename T1
, typename T2
>
195 explicit Optional_base(const T1
& aValue1
, const T2
& aValue2
) {
196 mImpl
.emplace(aValue1
, aValue2
);
199 bool WasPassed() const { return mImpl
.isSome(); }
201 // Return InternalType here so we can work with it usefully.
202 template <typename
... Args
>
203 InternalType
& Construct(Args
&&... aArgs
) {
204 mImpl
.emplace(std::forward
<Args
>(aArgs
)...);
208 void Reset() { mImpl
.reset(); }
210 const T
& Value() const { return *mImpl
; }
212 // Return InternalType here so we can work with it usefully.
213 InternalType
& Value() { return *mImpl
; }
215 // And an explicit way to get the InternalType even if we're const.
216 const InternalType
& InternalValue() const { return *mImpl
; }
218 // If we ever decide to add conversion operators for optional arrays
219 // like the ones Nullable has, we'll need to ensure that Maybe<> has
220 // the boolean before the actual data.
223 // Forbid copy-construction and assignment
224 Optional_base(const Optional_base
& other
) = delete;
225 const Optional_base
& operator=(const Optional_base
& other
) = delete;
228 Maybe
<InternalType
> mImpl
;
231 template <typename T
>
232 class Optional
: public Optional_base
<T
, T
> {
234 MOZ_ALLOW_TEMPORARY
Optional() : Optional_base
<T
, T
>() {}
236 explicit Optional(const T
& aValue
) : Optional_base
<T
, T
>(aValue
) {}
237 Optional(Optional
&&) = default;
240 template <typename T
>
241 class Optional
<JS::Handle
<T
>>
242 : public Optional_base
<JS::Handle
<T
>, JS::Rooted
<T
>> {
244 MOZ_ALLOW_TEMPORARY
Optional()
245 : Optional_base
<JS::Handle
<T
>, JS::Rooted
<T
>>() {}
247 explicit Optional(JSContext
* cx
)
248 : Optional_base
<JS::Handle
<T
>, JS::Rooted
<T
>>() {
252 Optional(JSContext
* cx
, const T
& aValue
)
253 : Optional_base
<JS::Handle
<T
>, JS::Rooted
<T
>>(cx
, aValue
) {}
255 // Override the const Value() to return the right thing so we're not
256 // returning references to temporaries.
257 JS::Handle
<T
> Value() const { return *this->mImpl
; }
259 // And we have to override the non-const one too, since we're
260 // shadowing the one on the superclass.
261 JS::Rooted
<T
>& Value() { return *this->mImpl
; }
264 // A specialization of Optional for JSObject* to make sure that when someone
265 // calls Construct() on it we will pre-initialized the JSObject* to nullptr so
266 // it can be traced safely.
268 class Optional
<JSObject
*> : public Optional_base
<JSObject
*, JSObject
*> {
270 Optional() = default;
272 explicit Optional(JSObject
* aValue
)
273 : Optional_base
<JSObject
*, JSObject
*>(aValue
) {}
275 // Don't allow us to have an uninitialized JSObject*
276 JSObject
*& Construct() {
277 // The Android compiler sucks and thinks we're trying to construct
278 // a JSObject* from an int if we don't cast here. :(
279 return Optional_base
<JSObject
*, JSObject
*>::Construct(
280 static_cast<JSObject
*>(nullptr));
284 JSObject
*& Construct(const T1
& t1
) {
285 return Optional_base
<JSObject
*, JSObject
*>::Construct(t1
);
289 // A specialization of Optional for JS::Value to make sure no one ever uses it.
291 class Optional
<JS::Value
> {
295 explicit Optional(const JS::Value
& aValue
) = delete;
298 // A specialization of Optional for NonNull that lets us get a T& from Value()
299 template <typename U
>
301 template <typename T
>
302 class Optional
<NonNull
<T
>> : public Optional_base
<T
, NonNull
<T
>> {
304 // We want our Value to actually return a non-const reference, even
305 // if we're const. At least for things that are normally pointer
307 T
& Value() const { return *this->mImpl
->get(); }
309 // And we have to override the non-const one too, since we're
310 // shadowing the one on the superclass.
311 NonNull
<T
>& Value() { return *this->mImpl
; }
314 // A specialization of Optional for OwningNonNull that lets us get a
316 template <typename T
>
317 class Optional
<OwningNonNull
<T
>> : public Optional_base
<T
, OwningNonNull
<T
>> {
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
322 T
& Value() const { return *this->mImpl
->get(); }
324 // And we have to override the non-const one too, since we're
325 // shadowing the one on the superclass.
326 OwningNonNull
<T
>& Value() { return *this->mImpl
; }
329 // Specialization for strings.
330 // XXXbz we can't pull in FakeString here, because it depends on internal
331 // strings. So we just have to forward-declare it and reimplement its
334 namespace binding_detail
{
335 template <typename CharT
>
337 } // namespace binding_detail
339 template <typename CharT
>
340 class Optional
<nsTSubstring
<CharT
>> {
341 using AString
= nsTSubstring
<CharT
>;
344 Optional() : mStr(nullptr) {}
346 bool WasPassed() const { return !!mStr
; }
348 void operator=(const AString
* str
) {
353 // If this code ever goes away, remove the comment pointing to it in the
354 // FakeString class in BindingUtils.h.
355 void operator=(const binding_detail::FakeString
<CharT
>* str
) {
357 mStr
= reinterpret_cast<const nsTString
<CharT
>*>(str
);
360 const AString
& Value() const {
361 MOZ_ASSERT(WasPassed());
366 // Forbid copy-construction and assignment
367 Optional(const Optional
& other
) = delete;
368 const Optional
& operator=(const Optional
& other
) = delete;
373 template <typename T
>
374 inline void ImplCycleCollectionUnlink(Optional
<T
>& aField
) {
375 if (aField
.WasPassed()) {
376 ImplCycleCollectionUnlink(aField
.Value());
380 template <typename T
>
381 inline void ImplCycleCollectionTraverse(
382 nsCycleCollectionTraversalCallback
& aCallback
, Optional
<T
>& aField
,
383 const char* aName
, uint32_t aFlags
= 0) {
384 if (aField
.WasPassed()) {
385 ImplCycleCollectionTraverse(aCallback
, aField
.Value(), aName
, aFlags
);
399 // This is no worse than get() in terms of const handling.
400 operator T
&() const {
402 MOZ_ASSERT(ptr
, "NonNull<T> was set to null");
406 operator T
*() const {
408 MOZ_ASSERT(ptr
, "NonNull<T> was set to null");
412 void operator=(T
* t
) {
420 template <typename U
>
421 void operator=(U
* t
) {
422 ptr
= t
->ToAStringPtr();
438 MOZ_ASSERT(ptr
, "NonNull<T> was set to null");
442 // Make us work with smart-ptr helpers that expect a get()
450 // ptr is left uninitialized for optimization purposes.
451 MOZ_INIT_OUTSIDE_CTOR T
* ptr
;
457 // Class for representing sequences in arguments. We use a non-auto array
458 // because that allows us to use sequences of sequences and the like. This
459 // needs to be fallible because web content controls the length of the array,
460 // and can easily try to create very large lengths.
461 template <typename T
>
462 class Sequence
: public FallibleTArray
<T
> {
464 Sequence() : FallibleTArray
<T
>() {}
465 MOZ_IMPLICIT
Sequence(FallibleTArray
<T
>&& aArray
)
466 : FallibleTArray
<T
>(std::move(aArray
)) {}
467 MOZ_IMPLICIT
Sequence(nsTArray
<T
>&& aArray
)
468 : FallibleTArray
<T
>(std::move(aArray
)) {}
470 Sequence(Sequence
&&) = default;
471 Sequence
& operator=(Sequence
&&) = default;
473 // XXX(Bug 1631461) Codegen.py must be adapted to allow making Sequence
475 Sequence(const Sequence
& aOther
) {
476 if (!this->AppendElements(aOther
, fallible
)) {
477 MOZ_CRASH("Out of memory");
480 Sequence
& operator=(const Sequence
& aOther
) {
481 if (this != &aOther
) {
483 if (!this->AppendElements(aOther
, fallible
)) {
484 MOZ_CRASH("Out of memory");
491 inline nsWrapperCache
* GetWrapperCache(nsWrapperCache
* cache
) { return cache
; }
493 inline nsWrapperCache
* GetWrapperCache(void* p
) { return nullptr; }
495 // Helper template for smart pointers to resolve ambiguity between
496 // GetWrappeCache(void*) and GetWrapperCache(const ParentObject&).
497 template <template <typename
> class SmartPtr
, typename T
>
498 inline nsWrapperCache
* GetWrapperCache(const SmartPtr
<T
>& aObject
) {
499 return GetWrapperCache(aObject
.get());
502 enum class ReflectionScope
{ Content
, NAC
, UAWidget
};
504 struct MOZ_STACK_CLASS ParentObject
{
506 MOZ_IMPLICIT
ParentObject(T
* aObject
)
507 : mObject(ToSupports(aObject
)),
508 mWrapperCache(GetWrapperCache(aObject
)),
509 mReflectionScope(ReflectionScope::Content
) {}
511 template <class T
, template <typename
> class SmartPtr
>
512 MOZ_IMPLICIT
ParentObject(const SmartPtr
<T
>& aObject
)
513 : mObject(aObject
.get()),
514 mWrapperCache(GetWrapperCache(aObject
.get())),
515 mReflectionScope(ReflectionScope::Content
) {}
517 ParentObject(nsISupports
* aObject
, nsWrapperCache
* aCache
)
519 mWrapperCache(aCache
),
520 mReflectionScope(ReflectionScope::Content
) {}
522 // We don't want to make this an nsCOMPtr because of performance reasons, but
523 // it's safe because ParentObject is a stack class.
524 nsISupports
* const MOZ_NON_OWNING_REF mObject
;
525 nsWrapperCache
* const mWrapperCache
;
526 ReflectionScope mReflectionScope
;
529 namespace binding_detail
{
531 // Class for simple sequence arguments, only used internally by codegen.
532 template <typename T
>
533 class AutoSequence
: public AutoTArray
<T
, 16> {
535 AutoSequence() : AutoTArray
<T
, 16>() {}
537 // Allow converting to const sequences as needed
538 operator const Sequence
<T
>&() const {
539 return *reinterpret_cast<const Sequence
<T
>*>(this);
543 } // namespace binding_detail
545 // Enum to represent a system or non-system caller type.
546 enum class CallerType
: uint32_t { System
, NonSystem
};
548 // A class that can be passed (by value or const reference) to indicate that the
549 // caller is always a system caller. This can be used as the type of an
550 // argument to force only system callers to call a function.
551 class SystemCallerGuarantee
{
553 operator CallerType() const { return CallerType::System
; }
556 class ProtoAndIfaceCache
;
557 typedef void (*CreateInterfaceObjectsMethod
)(JSContext
* aCx
,
558 JS::Handle
<JSObject
*> aGlobal
,
559 ProtoAndIfaceCache
& aCache
,
560 bool aDefineOnGlobal
);
561 JS::Handle
<JSObject
*> GetPerInterfaceObjectHandle(
562 JSContext
* aCx
, size_t aSlotId
, CreateInterfaceObjectsMethod aCreator
,
563 bool aDefineOnGlobal
);
566 } // namespace mozilla
568 #endif // mozilla_dom_BindingDeclarations_h__