tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

BindingDeclarations.h (17302B)


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