michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ 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: #ifndef mozilla_dom_DOMJSClass_h michael@0: #define mozilla_dom_DOMJSClass_h michael@0: michael@0: #include "jsfriendapi.h" michael@0: #include "mozilla/Assertions.h" michael@0: michael@0: #include "mozilla/dom/PrototypeList.h" // auto-generated michael@0: michael@0: #include "mozilla/dom/JSSlots.h" michael@0: michael@0: class nsCycleCollectionParticipant; michael@0: michael@0: // All DOM globals must have a slot at DOM_PROTOTYPE_SLOT. michael@0: #define DOM_PROTOTYPE_SLOT JSCLASS_GLOBAL_SLOT_COUNT michael@0: michael@0: // Keep this count up to date with any extra global slots added above. michael@0: #define DOM_GLOBAL_SLOTS 1 michael@0: michael@0: // We use these flag bits for the new bindings. michael@0: #define JSCLASS_DOM_GLOBAL JSCLASS_USERBIT1 michael@0: #define JSCLASS_IS_DOMIFACEANDPROTOJSCLASS JSCLASS_USERBIT2 michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: typedef bool michael@0: (* ResolveOwnProperty)(JSContext* cx, JS::Handle wrapper, michael@0: JS::Handle obj, JS::Handle id, michael@0: JS::MutableHandle desc); michael@0: michael@0: typedef bool michael@0: (* EnumerateOwnProperties)(JSContext* cx, JS::Handle wrapper, michael@0: JS::Handle obj, michael@0: JS::AutoIdVector& props); michael@0: michael@0: struct ConstantSpec michael@0: { michael@0: const char* name; michael@0: JS::Value value; michael@0: }; michael@0: michael@0: typedef bool (*PropertyEnabled)(JSContext* cx, JSObject* global); michael@0: michael@0: template michael@0: struct Prefable { michael@0: inline bool isEnabled(JSContext* cx, JSObject* obj) const { michael@0: if (!enabled) { michael@0: return false; michael@0: } michael@0: if (!enabledFunc && !availableFunc) { michael@0: return true; michael@0: } michael@0: // Just go ahead and root obj, in case enabledFunc GCs michael@0: JS::Rooted rootedObj(cx, obj); michael@0: if (enabledFunc && michael@0: !enabledFunc(cx, js::GetGlobalForObjectCrossCompartment(rootedObj))) { michael@0: return false; michael@0: } michael@0: if (availableFunc && michael@0: !availableFunc(cx, js::GetGlobalForObjectCrossCompartment(rootedObj))) { michael@0: return false; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: // A boolean indicating whether this set of specs is enabled michael@0: bool enabled; michael@0: // A function pointer to a function that can say the property is disabled michael@0: // even if "enabled" is set to true. If the pointer is null the value of michael@0: // "enabled" is used as-is unless availableFunc overrides. michael@0: PropertyEnabled enabledFunc; michael@0: // A function pointer to a function that can be used to disable a michael@0: // property even if "enabled" is true and enabledFunc allowed. This michael@0: // is basically a hack to avoid having to codegen PropertyEnabled michael@0: // implementations in case when we need to do two separate checks. michael@0: PropertyEnabled availableFunc; michael@0: // Array of specs, terminated in whatever way is customary for T. michael@0: // Null to indicate a end-of-array for Prefable, when such an michael@0: // indicator is needed. michael@0: const T* specs; michael@0: }; michael@0: michael@0: struct NativeProperties michael@0: { michael@0: const Prefable* staticMethods; michael@0: jsid* staticMethodIds; michael@0: const JSFunctionSpec* staticMethodsSpecs; michael@0: const Prefable* staticAttributes; michael@0: jsid* staticAttributeIds; michael@0: const JSPropertySpec* staticAttributeSpecs; michael@0: const Prefable* methods; michael@0: jsid* methodIds; michael@0: const JSFunctionSpec* methodsSpecs; michael@0: const Prefable* attributes; michael@0: jsid* attributeIds; michael@0: const JSPropertySpec* attributeSpecs; michael@0: const Prefable* unforgeableAttributes; michael@0: jsid* unforgeableAttributeIds; michael@0: const JSPropertySpec* unforgeableAttributeSpecs; michael@0: const Prefable* constants; michael@0: jsid* constantIds; michael@0: const ConstantSpec* constantSpecs; michael@0: }; michael@0: michael@0: struct NativePropertiesHolder michael@0: { michael@0: const NativeProperties* regular; michael@0: const NativeProperties* chromeOnly; michael@0: }; michael@0: michael@0: // Helper structure for Xrays for DOM binding objects. The same instance is used michael@0: // for instances, interface objects and interface prototype objects of a michael@0: // specific interface. michael@0: struct NativePropertyHooks michael@0: { michael@0: // The hook to call for resolving indexed or named properties. May be null if michael@0: // there can't be any. michael@0: ResolveOwnProperty mResolveOwnProperty; michael@0: // The hook to call for enumerating indexed or named properties. May be null michael@0: // if there can't be any. michael@0: EnumerateOwnProperties mEnumerateOwnProperties; michael@0: michael@0: // The property arrays for this interface. michael@0: NativePropertiesHolder mNativeProperties; michael@0: michael@0: // This will be set to the ID of the interface prototype object for the michael@0: // interface, if it has one. If it doesn't have one it will be set to michael@0: // prototypes::id::_ID_Count. michael@0: prototypes::ID mPrototypeID; michael@0: michael@0: // This will be set to the ID of the interface object for the interface, if it michael@0: // has one. If it doesn't have one it will be set to michael@0: // constructors::id::_ID_Count. michael@0: constructors::ID mConstructorID; michael@0: michael@0: // The NativePropertyHooks instance for the parent interface. michael@0: const NativePropertyHooks* mProtoHooks; michael@0: }; michael@0: michael@0: enum DOMObjectType { michael@0: eInstance, michael@0: eInterface, michael@0: eInterfacePrototype michael@0: }; michael@0: michael@0: typedef JSObject* (*ParentGetter)(JSContext* aCx, JS::Handle aObj); michael@0: /** michael@0: * Returns a handle to the relevent WebIDL prototype object for the given global michael@0: * (which may be a handle to null on out of memory). Once allocated, the michael@0: * prototype object is guaranteed to exist as long as the global does, since the michael@0: * global traces its array of WebIDL prototypes and constructors. michael@0: */ michael@0: typedef JS::Handle (*ProtoGetter)(JSContext* aCx, michael@0: JS::Handle aGlobal); michael@0: michael@0: struct DOMClass michael@0: { michael@0: // A list of interfaces that this object implements, in order of decreasing michael@0: // derivedness. michael@0: const prototypes::ID mInterfaceChain[MAX_PROTOTYPE_CHAIN_LENGTH]; michael@0: michael@0: // We store the DOM object in reserved slot with index DOM_OBJECT_SLOT or in michael@0: // the proxy private if we use a proxy object. michael@0: // Sometimes it's an nsISupports and sometimes it's not; this class tells michael@0: // us which it is. michael@0: const bool mDOMObjectIsISupports; michael@0: michael@0: const NativePropertyHooks* mNativeHooks; michael@0: michael@0: ParentGetter mGetParent; michael@0: ProtoGetter mGetProto; michael@0: michael@0: // This stores the CC participant for the native, null if this class is for a michael@0: // worker or for a native inheriting from nsISupports (we can get the CC michael@0: // participant by QI'ing in that case). michael@0: nsCycleCollectionParticipant* mParticipant; michael@0: }; michael@0: michael@0: // Special JSClass for reflected DOM objects. michael@0: struct DOMJSClass michael@0: { michael@0: // It would be nice to just inherit from JSClass, but that precludes pure michael@0: // compile-time initialization of the form |DOMJSClass = {...};|, since C++ michael@0: // only allows brace initialization for aggregate/POD types. michael@0: const js::Class mBase; michael@0: michael@0: const DOMClass mClass; michael@0: michael@0: static const DOMJSClass* FromJSClass(const JSClass* base) { michael@0: MOZ_ASSERT(base->flags & JSCLASS_IS_DOMJSCLASS); michael@0: return reinterpret_cast(base); michael@0: } michael@0: michael@0: static const DOMJSClass* FromJSClass(const js::Class* base) { michael@0: return FromJSClass(Jsvalify(base)); michael@0: } michael@0: michael@0: const JSClass* ToJSClass() const { return Jsvalify(&mBase); } michael@0: }; michael@0: michael@0: // Special JSClass for DOM interface and interface prototype objects. michael@0: struct DOMIfaceAndProtoJSClass michael@0: { michael@0: // It would be nice to just inherit from JSClass, but that precludes pure michael@0: // compile-time initialization of the form michael@0: // |DOMJSInterfaceAndPrototypeClass = {...};|, since C++ only allows brace michael@0: // initialization for aggregate/POD types. michael@0: const JSClass mBase; michael@0: michael@0: // Either eInterface or eInterfacePrototype michael@0: DOMObjectType mType; michael@0: michael@0: const NativePropertyHooks* mNativeHooks; michael@0: michael@0: // The value to return for toString() on this interface or interface prototype michael@0: // object. michael@0: const char* mToString; michael@0: michael@0: const prototypes::ID mPrototypeID; michael@0: const uint32_t mDepth; michael@0: michael@0: static const DOMIfaceAndProtoJSClass* FromJSClass(const JSClass* base) { michael@0: MOZ_ASSERT(base->flags & JSCLASS_IS_DOMIFACEANDPROTOJSCLASS); michael@0: return reinterpret_cast(base); michael@0: } michael@0: static const DOMIfaceAndProtoJSClass* FromJSClass(const js::Class* base) { michael@0: return FromJSClass(Jsvalify(base)); michael@0: } michael@0: michael@0: const JSClass* ToJSClass() const { return &mBase; } michael@0: }; michael@0: michael@0: class ProtoAndIfaceCache; michael@0: michael@0: inline bool michael@0: HasProtoAndIfaceCache(JSObject* global) michael@0: { michael@0: MOZ_ASSERT(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL); michael@0: // This can be undefined if we GC while creating the global michael@0: return !js::GetReservedSlot(global, DOM_PROTOTYPE_SLOT).isUndefined(); michael@0: } michael@0: michael@0: inline ProtoAndIfaceCache* michael@0: GetProtoAndIfaceCache(JSObject* global) michael@0: { michael@0: MOZ_ASSERT(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL); michael@0: return static_cast( michael@0: js::GetReservedSlot(global, DOM_PROTOTYPE_SLOT).toPrivate()); michael@0: } michael@0: michael@0: } // namespace dom michael@0: } // namespace mozilla michael@0: michael@0: #endif /* mozilla_dom_DOMJSClass_h */