michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ michael@0: /* vim: set ts=2 sw=2 et tw=79: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /** michael@0: * A header for declaring various things that binding implementation headers michael@0: * might need. The idea is to make binding implementation headers safe to michael@0: * include anywhere without running into include hell like we do with michael@0: * BindingUtils.h michael@0: */ michael@0: #ifndef mozilla_dom_BindingDeclarations_h__ michael@0: #define mozilla_dom_BindingDeclarations_h__ michael@0: michael@0: #include "nsStringGlue.h" michael@0: #include "js/Value.h" michael@0: #include "js/RootingAPI.h" michael@0: #include "mozilla/Maybe.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsTArray.h" michael@0: #include "nsAutoPtr.h" // for nsRefPtr member variables michael@0: #include "mozilla/dom/DOMString.h" michael@0: #include "mozilla/dom/OwningNonNull.h" michael@0: michael@0: class nsWrapperCache; michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: // Struct that serves as a base class for all dictionaries. Particularly useful michael@0: // so we can use IsBaseOf to detect dictionary template arguments. michael@0: struct DictionaryBase michael@0: { michael@0: protected: michael@0: bool ParseJSON(JSContext* aCx, const nsAString& aJSON, michael@0: JS::MutableHandle aVal); michael@0: }; michael@0: michael@0: // Struct that serves as a base class for all typed arrays and array buffers and michael@0: // array buffer views. Particularly useful so we can use IsBaseOf to detect michael@0: // typed array/buffer/view template arguments. michael@0: struct AllTypedArraysBase { michael@0: }; michael@0: michael@0: // Struct that serves as a base class for all owning unions. michael@0: // Particularly useful so we can use IsBaseOf to detect owning union michael@0: // template arguments. michael@0: struct AllOwningUnionBase { michael@0: }; michael@0: michael@0: michael@0: struct EnumEntry { michael@0: const char* value; michael@0: size_t length; michael@0: }; michael@0: michael@0: class MOZ_STACK_CLASS GlobalObject michael@0: { michael@0: public: michael@0: GlobalObject(JSContext* aCx, JSObject* aObject); michael@0: michael@0: JSObject* Get() const michael@0: { michael@0: return mGlobalJSObject; michael@0: } michael@0: michael@0: nsISupports* GetAsSupports() const; michael@0: michael@0: // The context that this returns is not guaranteed to be in the compartment of michael@0: // the object returned from Get(), in fact it's generally in the caller's michael@0: // compartment. michael@0: JSContext* GetContext() const michael@0: { michael@0: return mCx; michael@0: } michael@0: michael@0: bool Failed() const michael@0: { michael@0: return !Get(); michael@0: } michael@0: michael@0: protected: michael@0: JS::Rooted mGlobalJSObject; michael@0: JSContext* mCx; michael@0: mutable nsISupports* mGlobalObject; michael@0: mutable nsCOMPtr mGlobalObjectRef; michael@0: }; michael@0: michael@0: // Class for representing optional arguments. michael@0: template michael@0: class Optional_base michael@0: { michael@0: public: michael@0: Optional_base() michael@0: {} michael@0: michael@0: explicit Optional_base(const T& aValue) michael@0: { michael@0: mImpl.construct(aValue); michael@0: } michael@0: michael@0: template michael@0: explicit Optional_base(const T1& aValue1, const T2& aValue2) michael@0: { michael@0: mImpl.construct(aValue1, aValue2); michael@0: } michael@0: michael@0: bool WasPassed() const michael@0: { michael@0: return !mImpl.empty(); michael@0: } michael@0: michael@0: // Return InternalType here so we can work with it usefully. michael@0: InternalType& Construct() michael@0: { michael@0: mImpl.construct(); michael@0: return mImpl.ref(); michael@0: } michael@0: michael@0: template michael@0: InternalType& Construct(const T1 &t1) michael@0: { michael@0: mImpl.construct(t1); michael@0: return mImpl.ref(); michael@0: } michael@0: michael@0: template michael@0: InternalType& Construct(const T1 &t1, const T2 &t2) michael@0: { michael@0: mImpl.construct(t1, t2); michael@0: return mImpl.ref(); michael@0: } michael@0: michael@0: void Reset() michael@0: { michael@0: if (WasPassed()) { michael@0: mImpl.destroy(); michael@0: } michael@0: } michael@0: michael@0: const T& Value() const michael@0: { michael@0: return mImpl.ref(); michael@0: } michael@0: michael@0: // Return InternalType here so we can work with it usefully. michael@0: InternalType& Value() michael@0: { michael@0: return mImpl.ref(); michael@0: } michael@0: michael@0: // And an explicit way to get the InternalType even if we're const. michael@0: const InternalType& InternalValue() const michael@0: { michael@0: return mImpl.ref(); michael@0: } michael@0: michael@0: // If we ever decide to add conversion operators for optional arrays michael@0: // like the ones Nullable has, we'll need to ensure that Maybe<> has michael@0: // the boolean before the actual data. michael@0: michael@0: private: michael@0: // Forbid copy-construction and assignment michael@0: Optional_base(const Optional_base& other) MOZ_DELETE; michael@0: const Optional_base &operator=(const Optional_base &other) MOZ_DELETE; michael@0: michael@0: protected: michael@0: Maybe mImpl; michael@0: }; michael@0: michael@0: template michael@0: class Optional : public Optional_base michael@0: { michael@0: public: michael@0: Optional() : michael@0: Optional_base() michael@0: {} michael@0: michael@0: explicit Optional(const T& aValue) : michael@0: Optional_base(aValue) michael@0: {} michael@0: }; michael@0: michael@0: template michael@0: class Optional > : michael@0: public Optional_base, JS::Rooted > michael@0: { michael@0: public: michael@0: Optional() : michael@0: Optional_base, JS::Rooted >() michael@0: {} michael@0: michael@0: Optional(JSContext* cx) : michael@0: Optional_base, JS::Rooted >() michael@0: { michael@0: this->Construct(cx); michael@0: } michael@0: michael@0: Optional(JSContext* cx, const T& aValue) : michael@0: Optional_base, JS::Rooted >(cx, aValue) michael@0: {} michael@0: michael@0: // Override the const Value() to return the right thing so we're not michael@0: // returning references to temporaries. michael@0: JS::Handle Value() const michael@0: { michael@0: return this->mImpl.ref(); michael@0: } michael@0: michael@0: // And we have to override the non-const one too, since we're michael@0: // shadowing the one on the superclass. michael@0: JS::Rooted& Value() michael@0: { michael@0: return this->mImpl.ref(); michael@0: } michael@0: }; michael@0: michael@0: // A specialization of Optional for JSObject* to make sure that when someone michael@0: // calls Construct() on it we will pre-initialized the JSObject* to nullptr so michael@0: // it can be traced safely. michael@0: template<> michael@0: class Optional : public Optional_base michael@0: { michael@0: public: michael@0: Optional() : michael@0: Optional_base() michael@0: {} michael@0: michael@0: explicit Optional(JSObject* aValue) : michael@0: Optional_base(aValue) michael@0: {} michael@0: michael@0: // Don't allow us to have an uninitialized JSObject* michael@0: JSObject*& Construct() michael@0: { michael@0: // The Android compiler sucks and thinks we're trying to construct michael@0: // a JSObject* from an int if we don't cast here. :( michael@0: return Optional_base::Construct( michael@0: static_cast(nullptr)); michael@0: } michael@0: michael@0: template michael@0: JSObject*& Construct(const T1& t1) michael@0: { michael@0: return Optional_base::Construct(t1); michael@0: } michael@0: }; michael@0: michael@0: // A specialization of Optional for JS::Value to make sure no one ever uses it. michael@0: template<> michael@0: class Optional michael@0: { michael@0: private: michael@0: Optional() MOZ_DELETE; michael@0: michael@0: explicit Optional(JS::Value aValue) MOZ_DELETE; michael@0: }; michael@0: michael@0: // A specialization of Optional for NonNull that lets us get a T& from Value() michael@0: template class NonNull; michael@0: template michael@0: class Optional > : public Optional_base > michael@0: { michael@0: public: michael@0: // We want our Value to actually return a non-const reference, even michael@0: // if we're const. At least for things that are normally pointer michael@0: // types... michael@0: T& Value() const michael@0: { michael@0: return *this->mImpl.ref().get(); michael@0: } michael@0: michael@0: // And we have to override the non-const one too, since we're michael@0: // shadowing the one on the superclass. michael@0: NonNull& Value() michael@0: { michael@0: return this->mImpl.ref(); michael@0: } michael@0: }; michael@0: michael@0: // A specialization of Optional for OwningNonNull that lets us get a michael@0: // T& from Value() michael@0: template michael@0: class Optional > : public Optional_base > michael@0: { michael@0: public: michael@0: // We want our Value to actually return a non-const reference, even michael@0: // if we're const. At least for things that are normally pointer michael@0: // types... michael@0: T& Value() const michael@0: { michael@0: return *this->mImpl.ref().get(); michael@0: } michael@0: michael@0: // And we have to override the non-const one too, since we're michael@0: // shadowing the one on the superclass. michael@0: OwningNonNull& Value() michael@0: { michael@0: return this->mImpl.ref(); michael@0: } michael@0: }; michael@0: michael@0: // Specialization for strings. michael@0: // XXXbz we can't pull in FakeDependentString here, because it depends on michael@0: // internal strings. So we just have to forward-declare it and reimplement its michael@0: // ToAStringPtr. michael@0: michael@0: namespace binding_detail { michael@0: struct FakeDependentString; michael@0: } // namespace binding_detail michael@0: michael@0: template<> michael@0: class Optional michael@0: { michael@0: public: michael@0: Optional() : mPassed(false) {} michael@0: michael@0: bool WasPassed() const michael@0: { michael@0: return mPassed; michael@0: } michael@0: michael@0: void operator=(const nsAString* str) michael@0: { michael@0: MOZ_ASSERT(str); michael@0: mStr = str; michael@0: mPassed = true; michael@0: } michael@0: michael@0: // If this code ever goes away, remove the comment pointing to it in the michael@0: // FakeDependentString class in BindingUtils.h. michael@0: void operator=(const binding_detail::FakeDependentString* str) michael@0: { michael@0: MOZ_ASSERT(str); michael@0: mStr = reinterpret_cast(str); michael@0: mPassed = true; michael@0: } michael@0: michael@0: const nsAString& Value() const michael@0: { michael@0: MOZ_ASSERT(WasPassed()); michael@0: return *mStr; michael@0: } michael@0: michael@0: private: michael@0: // Forbid copy-construction and assignment michael@0: Optional(const Optional& other) MOZ_DELETE; michael@0: const Optional &operator=(const Optional &other) MOZ_DELETE; michael@0: michael@0: bool mPassed; michael@0: const nsAString* mStr; michael@0: }; michael@0: michael@0: template michael@0: class NonNull michael@0: { michael@0: public: michael@0: NonNull() michael@0: #ifdef DEBUG michael@0: : inited(false) michael@0: #endif michael@0: {} michael@0: michael@0: operator T&() { michael@0: MOZ_ASSERT(inited); michael@0: MOZ_ASSERT(ptr, "NonNull was set to null"); michael@0: return *ptr; michael@0: } michael@0: michael@0: operator const T&() const { michael@0: MOZ_ASSERT(inited); michael@0: MOZ_ASSERT(ptr, "NonNull was set to null"); michael@0: return *ptr; michael@0: } michael@0: michael@0: operator T*() { michael@0: MOZ_ASSERT(inited); michael@0: MOZ_ASSERT(ptr, "NonNull was set to null"); michael@0: return ptr; michael@0: } michael@0: michael@0: void operator=(T* t) { michael@0: ptr = t; michael@0: MOZ_ASSERT(ptr); michael@0: #ifdef DEBUG michael@0: inited = true; michael@0: #endif michael@0: } michael@0: michael@0: template michael@0: void operator=(U* t) { michael@0: ptr = t->ToAStringPtr(); michael@0: MOZ_ASSERT(ptr); michael@0: #ifdef DEBUG michael@0: inited = true; michael@0: #endif michael@0: } michael@0: michael@0: T** Slot() { michael@0: #ifdef DEBUG michael@0: inited = true; michael@0: #endif michael@0: return &ptr; michael@0: } michael@0: michael@0: T* Ptr() { michael@0: MOZ_ASSERT(inited); michael@0: MOZ_ASSERT(ptr, "NonNull was set to null"); michael@0: return ptr; michael@0: } michael@0: michael@0: // Make us work with smart-ptr helpers that expect a get() michael@0: T* get() const { michael@0: MOZ_ASSERT(inited); michael@0: MOZ_ASSERT(ptr); michael@0: return ptr; michael@0: } michael@0: michael@0: protected: michael@0: T* ptr; michael@0: #ifdef DEBUG michael@0: bool inited; michael@0: #endif michael@0: }; michael@0: michael@0: // Class for representing sequences in arguments. We use a non-auto array michael@0: // because that allows us to use sequences of sequences and the like. This michael@0: // needs to be fallible because web content controls the length of the array, michael@0: // and can easily try to create very large lengths. michael@0: template michael@0: class Sequence : public FallibleTArray michael@0: { michael@0: public: michael@0: Sequence() : FallibleTArray() michael@0: {} michael@0: }; michael@0: michael@0: inline nsWrapperCache* michael@0: GetWrapperCache(nsWrapperCache* cache) michael@0: { michael@0: return cache; michael@0: } michael@0: michael@0: inline nsWrapperCache* michael@0: GetWrapperCache(void* p) michael@0: { michael@0: return nullptr; michael@0: } michael@0: michael@0: // Helper template for smart pointers to resolve ambiguity between michael@0: // GetWrappeCache(void*) and GetWrapperCache(const ParentObject&). michael@0: template