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__