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=80: */ 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 michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef nsDOMClassInfo_h___ michael@0: #define nsDOMClassInfo_h___ michael@0: michael@0: #include "mozilla/Attributes.h" michael@0: #include "nsIXPCScriptable.h" michael@0: #include "nsIScriptGlobalObject.h" michael@0: #include "nsIDOMScriptObjectFactory.h" michael@0: #include "js/Id.h" michael@0: #include "nsIXPConnect.h" michael@0: michael@0: #ifdef XP_WIN michael@0: #undef GetClassName michael@0: #endif michael@0: michael@0: class nsContentList; michael@0: class nsDocument; michael@0: struct nsGlobalNameStruct; michael@0: class nsGlobalWindow; michael@0: class nsIScriptSecurityManager; michael@0: michael@0: struct nsDOMClassInfoData; michael@0: michael@0: typedef nsIClassInfo* (*nsDOMClassInfoConstructorFnc) michael@0: (nsDOMClassInfoData* aData); michael@0: michael@0: typedef nsresult (*nsDOMConstructorFunc)(nsISupports** aNewObject); michael@0: michael@0: struct nsDOMClassInfoData michael@0: { michael@0: const char *mName; michael@0: const char16_t *mNameUTF16; michael@0: union { michael@0: nsDOMClassInfoConstructorFnc mConstructorFptr; michael@0: nsDOMClassInfoExternalConstructorFnc mExternalConstructorFptr; michael@0: } u; michael@0: michael@0: nsIClassInfo *mCachedClassInfo; // low bit is set to 1 if external, michael@0: // so be sure to mask if necessary! michael@0: const nsIID *mProtoChainInterface; michael@0: const nsIID **mInterfaces; michael@0: uint32_t mScriptableFlags : 31; // flags must not use more than 31 bits! michael@0: uint32_t mHasClassInterface : 1; michael@0: uint32_t mInterfacesBitmap; michael@0: bool mChromeOnly : 1; michael@0: bool mAllowXBL : 1; michael@0: bool mDisabled : 1; michael@0: #ifdef DEBUG michael@0: uint32_t mDebugID; michael@0: #endif michael@0: }; michael@0: michael@0: struct nsExternalDOMClassInfoData : public nsDOMClassInfoData michael@0: { michael@0: const nsCID *mConstructorCID; michael@0: }; michael@0: michael@0: michael@0: // To be used with the nsDOMClassInfoData::mCachedClassInfo pointer. michael@0: // The low bit is set when we created a generic helper for an external michael@0: // (which holds on to the nsDOMClassInfoData). michael@0: #define GET_CLEAN_CI_PTR(_ptr) (nsIClassInfo*)(uintptr_t(_ptr) & ~0x1) michael@0: #define MARK_EXTERNAL(_ptr) (nsIClassInfo*)(uintptr_t(_ptr) | 0x1) michael@0: #define IS_EXTERNAL(_ptr) (uintptr_t(_ptr) & 0x1) michael@0: michael@0: michael@0: class nsDOMClassInfo : public nsXPCClassInfo michael@0: { michael@0: friend class nsHTMLDocumentSH; michael@0: public: michael@0: nsDOMClassInfo(nsDOMClassInfoData* aData); michael@0: virtual ~nsDOMClassInfo(); michael@0: michael@0: NS_DECL_NSIXPCSCRIPTABLE michael@0: michael@0: NS_DECL_ISUPPORTS michael@0: michael@0: NS_DECL_NSICLASSINFO michael@0: michael@0: // Helper method that returns a *non* refcounted pointer to a michael@0: // helper. So please note, don't release this pointer, if you do, michael@0: // you better make sure you've addreffed before release. michael@0: // michael@0: // Whaaaaa! I wanted to name this method GetClassInfo, but nooo, michael@0: // some of Microsoft devstudio's headers #defines GetClassInfo to michael@0: // GetClassInfoA so I can't, those $%#@^! bastards!!! What gives michael@0: // them the right to do that? michael@0: michael@0: static nsIClassInfo* GetClassInfoInstance(nsDOMClassInfoData* aData); michael@0: michael@0: static void ShutDown(); michael@0: michael@0: static nsIClassInfo *doCreate(nsDOMClassInfoData* aData) michael@0: { michael@0: return new nsDOMClassInfo(aData); michael@0: } michael@0: michael@0: /* michael@0: * The following two functions exist because of the way that Xray wrappers michael@0: * work. In order to allow scriptable helpers to define non-IDL defined but michael@0: * still "safe" properties for Xray wrappers, we call into the scriptable michael@0: * helper with |obj| being the wrapper. michael@0: * michael@0: * Ideally, that would be the end of the story, however due to complications michael@0: * dealing with document.domain, it's possible to end up in a scriptable michael@0: * helper with a wrapper, even though we should be treating the lookup as a michael@0: * transparent one. michael@0: * michael@0: * Note: So ObjectIsNativeWrapper(cx, obj) check usually means "through xray michael@0: * wrapper this part is not visible" while combined with michael@0: * || xpc::WrapperFactory::XrayWrapperNotShadowing(obj) it means "through michael@0: * xray wrapper it is visible only if it does not hide any native property." michael@0: */ michael@0: static bool ObjectIsNativeWrapper(JSContext* cx, JSObject* obj); michael@0: michael@0: static nsISupports *GetNative(nsIXPConnectWrappedNative *wrapper, JSObject *obj); michael@0: michael@0: static nsIXPConnect *XPConnect() michael@0: { michael@0: return sXPConnect; michael@0: } michael@0: static nsIScriptSecurityManager *ScriptSecurityManager() michael@0: { michael@0: return sSecMan; michael@0: } michael@0: michael@0: protected: michael@0: friend nsIClassInfo* NS_GetDOMClassInfoInstance(nsDOMClassInfoID aID); michael@0: michael@0: const nsDOMClassInfoData* mData; michael@0: michael@0: virtual void PreserveWrapper(nsISupports *aNative) MOZ_OVERRIDE michael@0: { michael@0: } michael@0: michael@0: virtual uint32_t GetInterfacesBitmap() MOZ_OVERRIDE michael@0: { michael@0: return mData->mInterfacesBitmap; michael@0: } michael@0: michael@0: static nsresult Init(); michael@0: static nsresult RegisterClassProtos(int32_t aDOMClassInfoID); michael@0: static nsresult RegisterExternalClasses(); michael@0: nsresult ResolveConstructor(JSContext *cx, JSObject *obj, michael@0: JSObject **objp); michael@0: michael@0: // Checks if id is a number and returns the number, if aIsNumber is michael@0: // non-null it's set to true if the id is a number and false if it's michael@0: // not a number. If id is not a number this method returns -1 michael@0: static int32_t GetArrayIndexFromId(JSContext *cx, JS::Handle id, michael@0: bool *aIsNumber = nullptr); michael@0: michael@0: static nsIXPConnect *sXPConnect; michael@0: static nsIScriptSecurityManager *sSecMan; michael@0: michael@0: // nsIXPCScriptable code michael@0: static nsresult DefineStaticJSVals(JSContext *cx); michael@0: michael@0: static bool sIsInitialized; michael@0: michael@0: public: michael@0: static jsid sLocation_id; michael@0: static jsid sConstructor_id; michael@0: static jsid sLength_id; michael@0: static jsid sItem_id; michael@0: static jsid sNamedItem_id; michael@0: static jsid sEnumerate_id; michael@0: static jsid sTop_id; michael@0: static jsid sDocument_id; michael@0: static jsid sWrappedJSObject_id; michael@0: }; michael@0: michael@0: // THIS ONE ISN'T SAFE!! It assumes that the private of the JSObject is michael@0: // an nsISupports. michael@0: inline michael@0: const nsQueryInterface michael@0: do_QueryWrappedNative(nsIXPConnectWrappedNative *wrapper, JSObject *obj) michael@0: { michael@0: return nsQueryInterface(nsDOMClassInfo::GetNative(wrapper, obj)); michael@0: } michael@0: michael@0: // THIS ONE ISN'T SAFE!! It assumes that the private of the JSObject is michael@0: // an nsISupports. michael@0: inline michael@0: const nsQueryInterfaceWithError michael@0: do_QueryWrappedNative(nsIXPConnectWrappedNative *wrapper, JSObject *obj, michael@0: nsresult *aError) michael@0: michael@0: { michael@0: return nsQueryInterfaceWithError(nsDOMClassInfo::GetNative(wrapper, obj), michael@0: aError); michael@0: } michael@0: michael@0: inline michael@0: nsQueryInterface michael@0: do_QueryWrapper(JSContext *cx, JSObject *obj) michael@0: { michael@0: nsISupports *native = michael@0: nsDOMClassInfo::XPConnect()->GetNativeOfWrapper(cx, obj); michael@0: return nsQueryInterface(native); michael@0: } michael@0: michael@0: inline michael@0: nsQueryInterfaceWithError michael@0: do_QueryWrapper(JSContext *cx, JSObject *obj, nsresult* error) michael@0: { michael@0: nsISupports *native = michael@0: nsDOMClassInfo::XPConnect()->GetNativeOfWrapper(cx, obj); michael@0: return nsQueryInterfaceWithError(native, error); michael@0: } michael@0: michael@0: michael@0: typedef nsDOMClassInfo nsDOMGenericSH; michael@0: michael@0: // Makes sure that the wrapper is preserved if new properties are added. michael@0: class nsEventTargetSH : public nsDOMGenericSH michael@0: { michael@0: protected: michael@0: nsEventTargetSH(nsDOMClassInfoData* aData) : nsDOMGenericSH(aData) michael@0: { michael@0: } michael@0: michael@0: virtual ~nsEventTargetSH() michael@0: { michael@0: } michael@0: public: michael@0: NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx, michael@0: JSObject *globalObj, JSObject **parentObj) MOZ_OVERRIDE; michael@0: NS_IMETHOD AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, jsid id, JS::Value *vp, bool *_retval) MOZ_OVERRIDE; michael@0: michael@0: virtual void PreserveWrapper(nsISupports *aNative) MOZ_OVERRIDE; michael@0: michael@0: static nsIClassInfo *doCreate(nsDOMClassInfoData* aData) michael@0: { michael@0: return new nsEventTargetSH(aData); michael@0: } michael@0: }; michael@0: michael@0: // Window scriptable helper michael@0: michael@0: class nsWindowSH : public nsDOMGenericSH michael@0: { michael@0: protected: michael@0: nsWindowSH(nsDOMClassInfoData *aData) : nsDOMGenericSH(aData) michael@0: { michael@0: } michael@0: michael@0: virtual ~nsWindowSH() michael@0: { michael@0: } michael@0: michael@0: static nsresult GlobalResolve(nsGlobalWindow *aWin, JSContext *cx, michael@0: JS::Handle obj, JS::Handle id, michael@0: JS::MutableHandle desc); michael@0: michael@0: friend class nsGlobalWindow; michael@0: public: michael@0: NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx, michael@0: JSObject *globalObj, JSObject **parentObj) MOZ_OVERRIDE; michael@0: NS_IMETHOD PostCreatePrototype(JSContext * cx, JSObject * proto) MOZ_OVERRIDE; michael@0: NS_IMETHOD PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj) MOZ_OVERRIDE; michael@0: NS_IMETHOD Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, bool *_retval) MOZ_OVERRIDE; michael@0: NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, jsid id, JSObject **objp, michael@0: bool *_retval) MOZ_OVERRIDE; michael@0: NS_IMETHOD OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx, michael@0: JSObject * obj, JSObject * *_retval) MOZ_OVERRIDE; michael@0: michael@0: static bool NameStructEnabled(JSContext* aCx, nsGlobalWindow *aWin, michael@0: const nsAString& aName, michael@0: const nsGlobalNameStruct& aNameStruct); michael@0: michael@0: static nsIClassInfo *doCreate(nsDOMClassInfoData* aData) michael@0: { michael@0: return new nsWindowSH(aData); michael@0: } michael@0: }; michael@0: michael@0: // Location scriptable helper michael@0: michael@0: class nsLocationSH : public nsDOMGenericSH michael@0: { michael@0: protected: michael@0: nsLocationSH(nsDOMClassInfoData* aData) : nsDOMGenericSH(aData) michael@0: { michael@0: } michael@0: michael@0: virtual ~nsLocationSH() michael@0: { michael@0: } michael@0: michael@0: public: michael@0: NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx, michael@0: JSObject *globalObj, JSObject **parentObj) MOZ_OVERRIDE; michael@0: NS_IMETHODIMP AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, jsid id, JS::Value *vp, bool *_retval); michael@0: michael@0: static nsIClassInfo *doCreate(nsDOMClassInfoData* aData) michael@0: { michael@0: return new nsLocationSH(aData); michael@0: } michael@0: }; michael@0: michael@0: michael@0: // Generic array scriptable helper michael@0: michael@0: class nsGenericArraySH : public nsDOMClassInfo michael@0: { michael@0: protected: michael@0: nsGenericArraySH(nsDOMClassInfoData* aData) : nsDOMClassInfo(aData) michael@0: { michael@0: } michael@0: michael@0: virtual ~nsGenericArraySH() michael@0: { michael@0: } michael@0: michael@0: public: michael@0: NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, jsid id, JSObject **objp, michael@0: bool *_retval) MOZ_OVERRIDE; michael@0: NS_IMETHOD Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, bool *_retval) MOZ_OVERRIDE; michael@0: michael@0: virtual nsresult GetLength(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JS::Handle obj, uint32_t *length); michael@0: michael@0: static nsIClassInfo *doCreate(nsDOMClassInfoData* aData) michael@0: { michael@0: return new nsGenericArraySH(aData); michael@0: } michael@0: }; michael@0: michael@0: michael@0: // Array scriptable helper michael@0: michael@0: class nsArraySH : public nsGenericArraySH michael@0: { michael@0: protected: michael@0: nsArraySH(nsDOMClassInfoData* aData) : nsGenericArraySH(aData) michael@0: { michael@0: } michael@0: michael@0: virtual ~nsArraySH() michael@0: { michael@0: } michael@0: michael@0: // Subclasses need to override this, if the implementation can't fail it's michael@0: // allowed to not set *aResult. michael@0: virtual nsISupports* GetItemAt(nsISupports *aNative, uint32_t aIndex, michael@0: nsWrapperCache **aCache, nsresult *aResult) = 0; michael@0: michael@0: public: michael@0: NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, jsid id, JS::Value *vp, bool *_retval) MOZ_OVERRIDE; michael@0: michael@0: private: michael@0: // Not implemented, nothing should create an instance of this class. michael@0: static nsIClassInfo *doCreate(nsDOMClassInfoData* aData); michael@0: }; michael@0: michael@0: michael@0: // CSSRuleList helper michael@0: michael@0: class nsCSSRuleListSH : public nsArraySH michael@0: { michael@0: protected: michael@0: nsCSSRuleListSH(nsDOMClassInfoData* aData) : nsArraySH(aData) michael@0: { michael@0: } michael@0: michael@0: virtual ~nsCSSRuleListSH() michael@0: { michael@0: } michael@0: michael@0: virtual nsISupports* GetItemAt(nsISupports *aNative, uint32_t aIndex, michael@0: nsWrapperCache **aCache, nsresult *aResult) MOZ_OVERRIDE; michael@0: michael@0: public: michael@0: static nsIClassInfo *doCreate(nsDOMClassInfoData* aData) michael@0: { michael@0: return new nsCSSRuleListSH(aData); michael@0: } michael@0: }; michael@0: michael@0: // WebApps Storage helpers michael@0: michael@0: class nsStorage2SH : public nsDOMGenericSH michael@0: { michael@0: protected: michael@0: nsStorage2SH(nsDOMClassInfoData* aData) : nsDOMGenericSH(aData) michael@0: { michael@0: } michael@0: michael@0: virtual ~nsStorage2SH() michael@0: { michael@0: } michael@0: michael@0: NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, jsid id, JSObject **objp, michael@0: bool *_retval) MOZ_OVERRIDE; michael@0: NS_IMETHOD SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, jsid id, JS::Value *vp, bool *_retval) MOZ_OVERRIDE; michael@0: NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, jsid id, JS::Value *vp, bool *_retval) MOZ_OVERRIDE; michael@0: NS_IMETHOD DelProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, jsid id, bool *_retval) MOZ_OVERRIDE; michael@0: NS_IMETHOD NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, uint32_t enum_op, JS::Value *statep, michael@0: jsid *idp, bool *_retval) MOZ_OVERRIDE; michael@0: michael@0: public: michael@0: static nsIClassInfo *doCreate(nsDOMClassInfoData* aData) michael@0: { michael@0: return new nsStorage2SH(aData); michael@0: } michael@0: }; michael@0: michael@0: // Event handler 'this' translator class, this is called by XPConnect michael@0: // when a "function interface" (nsIDOMEventListener) is called, this michael@0: // class extracts 'this' fomr the first argument to the called michael@0: // function (nsIDOMEventListener::HandleEvent(in nsIDOMEvent)), this michael@0: // class will pass back nsIDOMEvent::currentTarget to be used as michael@0: // 'this'. michael@0: michael@0: class nsEventListenerThisTranslator : public nsIXPCFunctionThisTranslator michael@0: { michael@0: public: michael@0: nsEventListenerThisTranslator() michael@0: { michael@0: } michael@0: michael@0: virtual ~nsEventListenerThisTranslator() michael@0: { michael@0: } michael@0: michael@0: // nsISupports michael@0: NS_DECL_ISUPPORTS michael@0: michael@0: // nsIXPCFunctionThisTranslator michael@0: NS_DECL_NSIXPCFUNCTIONTHISTRANSLATOR michael@0: }; michael@0: michael@0: class nsDOMConstructorSH : public nsDOMGenericSH michael@0: { michael@0: protected: michael@0: nsDOMConstructorSH(nsDOMClassInfoData* aData) : nsDOMGenericSH(aData) michael@0: { michael@0: } michael@0: michael@0: public: michael@0: NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx, michael@0: JSObject *globalObj, JSObject **parentObj) MOZ_OVERRIDE; michael@0: NS_IMETHOD PostCreatePrototype(JSContext * cx, JSObject * proto) MOZ_OVERRIDE michael@0: { michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, jsid id, JSObject **objp, michael@0: bool *_retval) MOZ_OVERRIDE; michael@0: NS_IMETHOD Call(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, const JS::CallArgs &args, bool *_retval) MOZ_OVERRIDE; michael@0: michael@0: NS_IMETHOD Construct(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, const JS::CallArgs &args, bool *_retval) MOZ_OVERRIDE; michael@0: michael@0: NS_IMETHOD HasInstance(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, JS::Handle val, bool *bp, michael@0: bool *_retval); michael@0: michael@0: static nsIClassInfo *doCreate(nsDOMClassInfoData* aData) michael@0: { michael@0: return new nsDOMConstructorSH(aData); michael@0: } michael@0: }; michael@0: michael@0: class nsNonDOMObjectSH : public nsDOMGenericSH michael@0: { michael@0: protected: michael@0: nsNonDOMObjectSH(nsDOMClassInfoData* aData) : nsDOMGenericSH(aData) michael@0: { michael@0: } michael@0: michael@0: virtual ~nsNonDOMObjectSH() michael@0: { michael@0: } michael@0: michael@0: public: michael@0: NS_IMETHOD GetFlags(uint32_t *aFlags) MOZ_OVERRIDE; michael@0: michael@0: static nsIClassInfo *doCreate(nsDOMClassInfoData* aData) michael@0: { michael@0: return new nsNonDOMObjectSH(aData); michael@0: } michael@0: }; michael@0: michael@0: #endif /* nsDOMClassInfo_h___ */