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=78: */ 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: #include "mozilla/ArrayUtils.h" michael@0: // On top because they include basictypes.h: michael@0: #include "mozilla/dom/SmsFilter.h" michael@0: michael@0: #ifdef XP_WIN michael@0: #undef GetClassName michael@0: #endif michael@0: michael@0: // JavaScript includes michael@0: #include "jsapi.h" michael@0: #include "jsfriendapi.h" michael@0: #include "WrapperFactory.h" michael@0: #include "AccessCheck.h" michael@0: #include "XrayWrapper.h" michael@0: michael@0: #include "xpcpublic.h" michael@0: #include "xpcprivate.h" michael@0: #include "XPCWrapper.h" michael@0: michael@0: #include "mozilla/DOMEventTargetHelper.h" michael@0: #include "mozilla/dom/RegisterBindings.h" michael@0: michael@0: #include "nscore.h" michael@0: #include "nsDOMClassInfo.h" michael@0: #include "nsCRT.h" michael@0: #include "nsCRTGlue.h" michael@0: #include "nsICategoryManager.h" michael@0: #include "nsIComponentRegistrar.h" michael@0: #include "nsXPCOM.h" michael@0: #include "nsISupportsPrimitives.h" michael@0: #include "nsIXPConnect.h" michael@0: #include "nsIXPCSecurityManager.h" michael@0: #include "xptcall.h" michael@0: #include "nsTArray.h" michael@0: #include "nsDocument.h" // nsDOMStyleSheetList michael@0: #include "nsDOMBlobBuilder.h" michael@0: michael@0: // General helper includes michael@0: #include "nsGlobalWindow.h" michael@0: #include "nsIContent.h" michael@0: #include "nsIDocument.h" michael@0: #include "nsIDOMDocument.h" michael@0: #include "nsIDOMEvent.h" michael@0: #include "nsIDOMEventListener.h" michael@0: #include "nsContentUtils.h" michael@0: #include "nsCxPusher.h" michael@0: #include "nsIDOMWindowUtils.h" michael@0: #include "nsIDOMGlobalPropertyInitializer.h" michael@0: #include "nsLocation.h" michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/Telemetry.h" michael@0: michael@0: // Window scriptable helper includes michael@0: #include "nsIDocShell.h" michael@0: #include "nsIScriptExternalNameSet.h" michael@0: #include "nsJSUtils.h" michael@0: #include "nsScriptNameSpaceManager.h" michael@0: #include "nsIJSNativeInitializer.h" michael@0: #include "nsJSEnvironment.h" michael@0: michael@0: // DOM base includes michael@0: #include "nsIDOMLocation.h" michael@0: #include "nsIDOMWindow.h" michael@0: #include "nsPIDOMWindow.h" michael@0: #include "nsIDOMJSWindow.h" michael@0: #include "nsIDOMChromeWindow.h" michael@0: #include "nsIDOMConstructor.h" michael@0: michael@0: // DOM core includes michael@0: #include "nsError.h" michael@0: #include "nsIDOMUserDataHandler.h" michael@0: #include "nsIDOMXULButtonElement.h" michael@0: #include "nsIDOMXULCheckboxElement.h" michael@0: #include "nsIDOMXULPopupElement.h" michael@0: michael@0: // Event related includes michael@0: #include "nsIDOMEventTarget.h" michael@0: michael@0: // CSS related includes michael@0: #include "nsCSSRules.h" michael@0: #include "nsIDOMCSSRule.h" michael@0: #include "nsICSSRuleList.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsMemory.h" michael@0: michael@0: // Tranformiix michael@0: #include "nsIXSLTProcessor.h" michael@0: #include "nsIXSLTProcessorPrivate.h" michael@0: michael@0: // includes needed for the prototype chain interfaces michael@0: #include "nsIDOMCSSCharsetRule.h" michael@0: #include "nsIDOMCSSImportRule.h" michael@0: #include "nsIDOMCSSMediaRule.h" michael@0: #include "nsIDOMCSSFontFaceRule.h" michael@0: #include "nsIDOMCSSMozDocumentRule.h" michael@0: #include "nsIDOMCSSSupportsRule.h" michael@0: #include "nsIDOMMozCSSKeyframeRule.h" michael@0: #include "nsIDOMMozCSSKeyframesRule.h" michael@0: #include "nsIDOMCSSPageRule.h" michael@0: #include "nsIDOMCSSStyleRule.h" michael@0: #include "nsIDOMCSSStyleSheet.h" michael@0: #include "nsIDOMXULCommandDispatcher.h" michael@0: #include "nsIControllers.h" michael@0: #include "nsIBoxObject.h" michael@0: #ifdef MOZ_XUL michael@0: #include "nsITreeSelection.h" michael@0: #include "nsITreeContentView.h" michael@0: #include "nsITreeView.h" michael@0: #include "nsIXULTemplateBuilder.h" michael@0: #include "nsITreeColumns.h" michael@0: #endif michael@0: #include "nsIDOMXPathExpression.h" michael@0: #include "nsIDOMNSXPathExpression.h" michael@0: #include "nsIDOMXPathNSResolver.h" michael@0: #include "nsIDOMXPathResult.h" michael@0: michael@0: #include "nsIDOMSVGNumber.h" michael@0: michael@0: // Storage includes michael@0: #include "nsIDOMStorage.h" michael@0: #include "nsPIDOMStorage.h" michael@0: michael@0: // Drag and drop michael@0: #include "nsIDOMFile.h" michael@0: #include "nsDOMBlobBuilder.h" // nsDOMMultipartFile michael@0: michael@0: #include "nsIEventListenerService.h" michael@0: #include "nsIMessageManager.h" michael@0: michael@0: #include "mozilla/dom/TouchEvent.h" michael@0: michael@0: #include "nsWrapperCacheInlines.h" michael@0: #include "mozilla/dom/HTMLCollectionBinding.h" michael@0: michael@0: #include "nsIDOMMobileMessageManager.h" michael@0: #include "nsIDOMMozSmsMessage.h" michael@0: #include "nsIDOMMozMmsMessage.h" michael@0: #include "nsIDOMSmsFilter.h" michael@0: #include "nsIDOMSmsSegmentInfo.h" michael@0: #include "nsIDOMMozMobileMessageThread.h" michael@0: michael@0: #ifdef MOZ_B2G_RIL michael@0: #include "nsIDOMMobileConnection.h" michael@0: #endif // MOZ_B2G_RIL michael@0: michael@0: #ifdef MOZ_B2G_FM michael@0: #include "FMRadio.h" michael@0: #endif michael@0: michael@0: #include "nsIDOMGlobalObjectConstructor.h" michael@0: #include "nsDebug.h" michael@0: michael@0: #include "mozilla/dom/BindingUtils.h" michael@0: #include "mozilla/Likely.h" michael@0: #include "WindowNamedPropertiesHandler.h" michael@0: #include "nsIInterfaceInfoManager.h" michael@0: #include "mozilla/dom/EventTargetBinding.h" michael@0: #include "mozilla/dom/WindowBinding.h" michael@0: michael@0: #ifdef MOZ_TIME_MANAGER michael@0: #include "TimeManager.h" michael@0: #endif michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::dom; michael@0: michael@0: static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID); michael@0: michael@0: // NOTE: DEFAULT_SCRIPTABLE_FLAGS and DOM_DEFAULT_SCRIPTABLE_FLAGS michael@0: // are defined in nsIDOMClassInfo.h. michael@0: michael@0: #define WINDOW_SCRIPTABLE_FLAGS \ michael@0: (nsIXPCScriptable::WANT_PRECREATE | \ michael@0: nsIXPCScriptable::WANT_POSTCREATE | \ michael@0: nsIXPCScriptable::WANT_ENUMERATE | \ michael@0: nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE | \ michael@0: nsIXPCScriptable::IS_GLOBAL_OBJECT | \ michael@0: nsIXPCScriptable::WANT_OUTER_OBJECT) michael@0: michael@0: #define ARRAY_SCRIPTABLE_FLAGS \ michael@0: (DOM_DEFAULT_SCRIPTABLE_FLAGS | \ michael@0: nsIXPCScriptable::WANT_GETPROPERTY | \ michael@0: nsIXPCScriptable::WANT_ENUMERATE) michael@0: michael@0: #define EVENTTARGET_SCRIPTABLE_FLAGS \ michael@0: (DOM_DEFAULT_SCRIPTABLE_FLAGS | \ michael@0: nsIXPCScriptable::WANT_ADDPROPERTY) michael@0: michael@0: #define DOMCLASSINFO_STANDARD_FLAGS \ michael@0: (nsIClassInfo::MAIN_THREAD_ONLY | \ michael@0: nsIClassInfo::DOM_OBJECT | \ michael@0: nsIClassInfo::SINGLETON_CLASSINFO) michael@0: michael@0: michael@0: #ifdef DEBUG michael@0: #define NS_DEFINE_CLASSINFO_DATA_DEBUG(_class) \ michael@0: eDOMClassInfo_##_class##_id, michael@0: #else michael@0: #define NS_DEFINE_CLASSINFO_DATA_DEBUG(_class) \ michael@0: // nothing michael@0: #endif michael@0: michael@0: /** michael@0: * To generate the bitmap for a class that we're sure doesn't implement any of michael@0: * the interfaces in DOMCI_CASTABLE_INTERFACES. michael@0: */ michael@0: #define DOMCI_DATA_NO_CLASS(_dom_class) \ michael@0: const uint32_t kDOMClassInfo_##_dom_class##_interfaces = \ michael@0: 0; michael@0: michael@0: DOMCI_DATA_NO_CLASS(ContentFrameMessageManager) michael@0: DOMCI_DATA_NO_CLASS(ChromeMessageBroadcaster) michael@0: DOMCI_DATA_NO_CLASS(ChromeMessageSender) michael@0: michael@0: DOMCI_DATA_NO_CLASS(DOMPrototype) michael@0: DOMCI_DATA_NO_CLASS(DOMConstructor) michael@0: michael@0: DOMCI_DATA_NO_CLASS(UserDataHandler) michael@0: DOMCI_DATA_NO_CLASS(XULControlElement) michael@0: DOMCI_DATA_NO_CLASS(XULLabeledControlElement) michael@0: DOMCI_DATA_NO_CLASS(XULButtonElement) michael@0: DOMCI_DATA_NO_CLASS(XULCheckboxElement) michael@0: DOMCI_DATA_NO_CLASS(XULPopupElement) michael@0: michael@0: #define NS_DEFINE_CLASSINFO_DATA_HELPER(_class, _helper, _flags, \ michael@0: _chromeOnly, _allowXBL) \ michael@0: { #_class, \ michael@0: nullptr, \ michael@0: { _helper::doCreate }, \ michael@0: nullptr, \ michael@0: nullptr, \ michael@0: nullptr, \ michael@0: _flags, \ michael@0: true, \ michael@0: 0, \ michael@0: _chromeOnly, \ michael@0: _allowXBL, \ michael@0: false, \ michael@0: NS_DEFINE_CLASSINFO_DATA_DEBUG(_class) \ michael@0: }, michael@0: michael@0: #define NS_DEFINE_CLASSINFO_DATA(_class, _helper, _flags) \ michael@0: NS_DEFINE_CLASSINFO_DATA_HELPER(_class, _helper, _flags, false, false) michael@0: michael@0: #define NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(_class, _helper, _flags) \ michael@0: NS_DEFINE_CLASSINFO_DATA_HELPER(_class, _helper, _flags, true, false) michael@0: michael@0: #define NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(_class, _helper, _flags) \ michael@0: NS_DEFINE_CLASSINFO_DATA_HELPER(_class, _helper, _flags, true, true) michael@0: michael@0: michael@0: // This list of NS_DEFINE_CLASSINFO_DATA macros is what gives the DOM michael@0: // classes their correct behavior when used through XPConnect. The michael@0: // arguments that are passed to NS_DEFINE_CLASSINFO_DATA are michael@0: // michael@0: // 1. Class name as it should appear in JavaScript, this name is also michael@0: // used to find the id of the class in nsDOMClassInfo michael@0: // (i.e. e_id) michael@0: // 2. Scriptable helper class michael@0: // 3. nsIClassInfo/nsIXPCScriptable flags (i.e. for GetScriptableFlags) michael@0: michael@0: static nsDOMClassInfoData sClassInfoData[] = { michael@0: // Base classes michael@0: michael@0: // The Window class lets you QI into interfaces that are not in the michael@0: // flattened set (i.e. nsIXPCScriptable::CLASSINFO_INTERFACES_ONLY michael@0: // is not set), because of this make sure all scriptable interfaces michael@0: // that are implemented by nsGlobalWindow can securely be exposed michael@0: // to JS. michael@0: michael@0: michael@0: NS_DEFINE_CLASSINFO_DATA(Window, nsWindowSH, michael@0: DEFAULT_SCRIPTABLE_FLAGS | michael@0: WINDOW_SCRIPTABLE_FLAGS) michael@0: michael@0: NS_DEFINE_CLASSINFO_DATA(Location, nsLocationSH, michael@0: ((DOM_DEFAULT_SCRIPTABLE_FLAGS | michael@0: nsIXPCScriptable::WANT_ADDPROPERTY) & michael@0: ~nsIXPCScriptable::ALLOW_PROP_MODS_TO_PROTOTYPE)) michael@0: michael@0: NS_DEFINE_CLASSINFO_DATA(DOMPrototype, nsDOMConstructorSH, michael@0: DOM_BASE_SCRIPTABLE_FLAGS | michael@0: nsIXPCScriptable::WANT_PRECREATE | michael@0: nsIXPCScriptable::WANT_NEWRESOLVE | michael@0: nsIXPCScriptable::WANT_HASINSTANCE | michael@0: nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE) michael@0: NS_DEFINE_CLASSINFO_DATA(DOMConstructor, nsDOMConstructorSH, michael@0: DOM_BASE_SCRIPTABLE_FLAGS | michael@0: nsIXPCScriptable::WANT_PRECREATE | michael@0: nsIXPCScriptable::WANT_NEWRESOLVE | michael@0: nsIXPCScriptable::WANT_HASINSTANCE | michael@0: nsIXPCScriptable::WANT_CALL | michael@0: nsIXPCScriptable::WANT_CONSTRUCT | michael@0: nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE) michael@0: michael@0: // Misc Core related classes michael@0: michael@0: // CSS classes michael@0: NS_DEFINE_CLASSINFO_DATA(CSSStyleRule, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: NS_DEFINE_CLASSINFO_DATA(CSSCharsetRule, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: NS_DEFINE_CLASSINFO_DATA(CSSImportRule, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: NS_DEFINE_CLASSINFO_DATA(CSSMediaRule, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: NS_DEFINE_CLASSINFO_DATA(CSSNameSpaceRule, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: NS_DEFINE_CLASSINFO_DATA(CSSRuleList, nsCSSRuleListSH, michael@0: ARRAY_SCRIPTABLE_FLAGS) michael@0: NS_DEFINE_CLASSINFO_DATA(CSSStyleSheet, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: michael@0: // XUL classes michael@0: #ifdef MOZ_XUL michael@0: NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULCommandDispatcher, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: #endif michael@0: NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULControllers, nsNonDOMObjectSH, michael@0: DEFAULT_SCRIPTABLE_FLAGS) michael@0: NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(BoxObject, nsDOMGenericSH, michael@0: DEFAULT_SCRIPTABLE_FLAGS) michael@0: #ifdef MOZ_XUL michael@0: NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(TreeSelection, nsDOMGenericSH, michael@0: DEFAULT_SCRIPTABLE_FLAGS) michael@0: NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(TreeContentView, nsDOMGenericSH, michael@0: DEFAULT_SCRIPTABLE_FLAGS) michael@0: #endif michael@0: michael@0: // DOM Chrome Window class. michael@0: NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(ChromeWindow, nsWindowSH, michael@0: DEFAULT_SCRIPTABLE_FLAGS | michael@0: WINDOW_SCRIPTABLE_FLAGS) michael@0: michael@0: #ifdef MOZ_XUL michael@0: NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULTemplateBuilder, nsDOMGenericSH, michael@0: DEFAULT_SCRIPTABLE_FLAGS) michael@0: michael@0: NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULTreeBuilder, nsDOMGenericSH, michael@0: DEFAULT_SCRIPTABLE_FLAGS) michael@0: #endif michael@0: michael@0: #ifdef MOZ_XUL michael@0: NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(TreeColumn, nsDOMGenericSH, michael@0: DEFAULT_SCRIPTABLE_FLAGS) michael@0: #endif michael@0: michael@0: NS_DEFINE_CLASSINFO_DATA(CSSMozDocumentRule, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: michael@0: NS_DEFINE_CLASSINFO_DATA(CSSSupportsRule, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: michael@0: // other SVG classes michael@0: NS_DEFINE_CLASSINFO_DATA(SVGNumber, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: michael@0: NS_DEFINE_CLASSINFO_DATA(WindowUtils, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: michael@0: NS_DEFINE_CLASSINFO_DATA(XSLTProcessor, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: michael@0: NS_DEFINE_CLASSINFO_DATA(XPathExpression, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: NS_DEFINE_CLASSINFO_DATA(XPathNSResolver, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: NS_DEFINE_CLASSINFO_DATA(XPathResult, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: michael@0: // WhatWG Storage michael@0: michael@0: // mrbkap says we don't need WANT_ADDPROPERTY on Storage objects michael@0: // since a call to addProperty() is always followed by a call to michael@0: // setProperty(), except in the case when a getter or setter is set michael@0: // for a property. But we don't care about getters or setters here. michael@0: NS_DEFINE_CLASSINFO_DATA(Storage, nsStorage2SH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS | michael@0: nsIXPCScriptable::WANT_NEWRESOLVE | michael@0: nsIXPCScriptable::WANT_GETPROPERTY | michael@0: nsIXPCScriptable::WANT_SETPROPERTY | michael@0: nsIXPCScriptable::WANT_DELPROPERTY | michael@0: nsIXPCScriptable::DONT_ENUM_STATIC_PROPS | michael@0: nsIXPCScriptable::WANT_NEWENUMERATE) michael@0: michael@0: NS_DEFINE_CLASSINFO_DATA(Blob, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: NS_DEFINE_CLASSINFO_DATA(File, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: michael@0: NS_DEFINE_CLASSINFO_DATA(ModalContentWindow, nsWindowSH, michael@0: DEFAULT_SCRIPTABLE_FLAGS | michael@0: WINDOW_SCRIPTABLE_FLAGS) michael@0: michael@0: NS_DEFINE_CLASSINFO_DATA(MozMobileMessageManager, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: michael@0: NS_DEFINE_CLASSINFO_DATA(MozSmsMessage, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: michael@0: NS_DEFINE_CLASSINFO_DATA(MozMmsMessage, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: michael@0: NS_DEFINE_CLASSINFO_DATA(MozSmsFilter, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: michael@0: NS_DEFINE_CLASSINFO_DATA(MozSmsSegmentInfo, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: michael@0: NS_DEFINE_CLASSINFO_DATA(MozMobileMessageThread, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: michael@0: #ifdef MOZ_B2G_RIL michael@0: NS_DEFINE_CLASSINFO_DATA(MozMobileConnection, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: #endif michael@0: michael@0: NS_DEFINE_CLASSINFO_DATA(CSSFontFaceRule, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: michael@0: NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ContentFrameMessageManager, nsEventTargetSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS | michael@0: nsIXPCScriptable::IS_GLOBAL_OBJECT) michael@0: NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ChromeMessageBroadcaster, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ChromeMessageSender, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: michael@0: michael@0: NS_DEFINE_CLASSINFO_DATA(MozCSSKeyframeRule, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: NS_DEFINE_CLASSINFO_DATA(MozCSSKeyframesRule, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: michael@0: NS_DEFINE_CLASSINFO_DATA(CSSPageRule, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: michael@0: NS_DEFINE_CLASSINFO_DATA(CSSFontFeatureValuesRule, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: michael@0: NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(UserDataHandler, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULControlElement, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULLabeledControlElement, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULButtonElement, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULCheckboxElement, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULPopupElement, nsDOMGenericSH, michael@0: DOM_DEFAULT_SCRIPTABLE_FLAGS) michael@0: }; michael@0: michael@0: #define NS_DEFINE_CONTRACT_CTOR(_class, _contract_id) \ michael@0: static nsresult \ michael@0: _class##Ctor(nsISupports** aInstancePtrResult) \ michael@0: { \ michael@0: nsresult rv = NS_OK; \ michael@0: nsCOMPtr native = do_CreateInstance(_contract_id, &rv); \ michael@0: native.forget(aInstancePtrResult); \ michael@0: return rv; \ michael@0: } michael@0: michael@0: NS_DEFINE_CONTRACT_CTOR(XSLTProcessor, michael@0: "@mozilla.org/document-transformer;1?type=xslt") michael@0: michael@0: #undef NS_DEFINE_CONTRACT_CTOR michael@0: michael@0: struct nsConstructorFuncMapData michael@0: { michael@0: int32_t mDOMClassInfoID; michael@0: nsDOMConstructorFunc mConstructorFunc; michael@0: }; michael@0: michael@0: #define NS_DEFINE_CONSTRUCTOR_FUNC_DATA(_class, _func) \ michael@0: { eDOMClassInfo_##_class##_id, _func }, michael@0: michael@0: static const nsConstructorFuncMapData kConstructorFuncMap[] = michael@0: { michael@0: NS_DEFINE_CONSTRUCTOR_FUNC_DATA(Blob, nsDOMMultipartFile::NewBlob) michael@0: NS_DEFINE_CONSTRUCTOR_FUNC_DATA(File, nsDOMMultipartFile::NewFile) michael@0: NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MozSmsFilter, SmsFilter::NewSmsFilter) michael@0: NS_DEFINE_CONSTRUCTOR_FUNC_DATA(XSLTProcessor, XSLTProcessorCtor) michael@0: }; michael@0: #undef NS_DEFINE_CONSTRUCTOR_FUNC_DATA michael@0: michael@0: nsIXPConnect *nsDOMClassInfo::sXPConnect = nullptr; michael@0: nsIScriptSecurityManager *nsDOMClassInfo::sSecMan = nullptr; michael@0: bool nsDOMClassInfo::sIsInitialized = false; michael@0: michael@0: michael@0: jsid nsDOMClassInfo::sLocation_id = JSID_VOID; michael@0: jsid nsDOMClassInfo::sConstructor_id = JSID_VOID; michael@0: jsid nsDOMClassInfo::sLength_id = JSID_VOID; michael@0: jsid nsDOMClassInfo::sItem_id = JSID_VOID; michael@0: jsid nsDOMClassInfo::sNamedItem_id = JSID_VOID; michael@0: jsid nsDOMClassInfo::sEnumerate_id = JSID_VOID; michael@0: jsid nsDOMClassInfo::sTop_id = JSID_VOID; michael@0: jsid nsDOMClassInfo::sDocument_id = JSID_VOID; michael@0: jsid nsDOMClassInfo::sWrappedJSObject_id = JSID_VOID; michael@0: michael@0: static const JSClass *sObjectClass = nullptr; michael@0: michael@0: /** michael@0: * Set our JSClass pointer for the Object class michael@0: */ michael@0: static void michael@0: FindObjectClass(JSContext* cx, JSObject* aGlobalObject) michael@0: { michael@0: NS_ASSERTION(!sObjectClass, michael@0: "Double set of sObjectClass"); michael@0: JS::Rooted obj(cx), proto(cx, aGlobalObject); michael@0: do { michael@0: obj = proto; michael@0: js::GetObjectProto(cx, obj, &proto); michael@0: } while (proto); michael@0: michael@0: sObjectClass = js::GetObjectJSClass(obj); michael@0: } michael@0: michael@0: static inline JSString * michael@0: IdToString(JSContext *cx, jsid id) michael@0: { michael@0: if (JSID_IS_STRING(id)) michael@0: return JSID_TO_STRING(id); michael@0: JS::Rooted idval(cx); michael@0: if (!::JS_IdToValue(cx, id, &idval)) michael@0: return nullptr; michael@0: return JS::ToString(cx, idval); michael@0: } michael@0: michael@0: static inline nsresult michael@0: WrapNative(JSContext *cx, nsISupports *native, michael@0: nsWrapperCache *cache, const nsIID* aIID, JS::MutableHandle vp, michael@0: bool aAllowWrapping) michael@0: { michael@0: if (!native) { michael@0: vp.setNull(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: JSObject *wrapper = xpc_FastGetCachedWrapper(cx, cache, vp); michael@0: if (wrapper) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: JS::Rooted scope(cx, JS::CurrentGlobalOrNull(cx)); michael@0: return nsDOMClassInfo::XPConnect()->WrapNativeToJSVal(cx, scope, native, michael@0: cache, aIID, michael@0: aAllowWrapping, vp); michael@0: } michael@0: michael@0: static inline nsresult michael@0: WrapNative(JSContext *cx, nsISupports *native, const nsIID* aIID, michael@0: bool aAllowWrapping, JS::MutableHandle vp) michael@0: { michael@0: return WrapNative(cx, native, nullptr, aIID, vp, aAllowWrapping); michael@0: } michael@0: michael@0: // Same as the WrapNative above, but use these if aIID is nsISupports' IID. michael@0: static inline nsresult michael@0: WrapNative(JSContext *cx, nsISupports *native, michael@0: bool aAllowWrapping, JS::MutableHandle vp) michael@0: { michael@0: return WrapNative(cx, native, nullptr, nullptr, vp, aAllowWrapping); michael@0: } michael@0: michael@0: static inline nsresult michael@0: WrapNative(JSContext *cx, nsISupports *native, michael@0: nsWrapperCache *cache, bool aAllowWrapping, michael@0: JS::MutableHandle vp) michael@0: { michael@0: return WrapNative(cx, native, cache, nullptr, vp, aAllowWrapping); michael@0: } michael@0: michael@0: // Helper to handle torn-down inner windows. michael@0: static inline nsresult michael@0: SetParentToWindow(nsGlobalWindow *win, JSObject **parent) michael@0: { michael@0: MOZ_ASSERT(win); michael@0: MOZ_ASSERT(win->IsInnerWindow()); michael@0: *parent = win->FastGetGlobalJSObject(); michael@0: michael@0: if (MOZ_UNLIKELY(!*parent)) { michael@0: // The inner window has been torn down. The scope is dying, so don't create michael@0: // any new wrappers. michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: // static michael@0: michael@0: nsISupports * michael@0: nsDOMClassInfo::GetNative(nsIXPConnectWrappedNative *wrapper, JSObject *obj) michael@0: { michael@0: return wrapper ? wrapper->Native() : static_cast(js::GetObjectPrivate(obj)); michael@0: } michael@0: michael@0: nsresult michael@0: nsDOMClassInfo::DefineStaticJSVals(JSContext *cx) michael@0: { michael@0: #define SET_JSID_TO_STRING(_id, _cx, _str) \ michael@0: if (JSString *str = ::JS_InternString(_cx, _str)) \ michael@0: _id = INTERNED_STRING_TO_JSID(_cx, str); \ michael@0: else \ michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: SET_JSID_TO_STRING(sLocation_id, cx, "location"); michael@0: SET_JSID_TO_STRING(sConstructor_id, cx, "constructor"); michael@0: SET_JSID_TO_STRING(sLength_id, cx, "length"); michael@0: SET_JSID_TO_STRING(sItem_id, cx, "item"); michael@0: SET_JSID_TO_STRING(sNamedItem_id, cx, "namedItem"); michael@0: SET_JSID_TO_STRING(sEnumerate_id, cx, "enumerateProperties"); michael@0: SET_JSID_TO_STRING(sTop_id, cx, "top"); michael@0: SET_JSID_TO_STRING(sDocument_id, cx, "document"); michael@0: SET_JSID_TO_STRING(sWrappedJSObject_id, cx, "wrappedJSObject"); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // static michael@0: bool michael@0: nsDOMClassInfo::ObjectIsNativeWrapper(JSContext* cx, JSObject* obj) michael@0: { michael@0: return xpc::WrapperFactory::IsXrayWrapper(obj) && michael@0: xpc::AccessCheck::wrapperSubsumes(obj); michael@0: } michael@0: michael@0: nsDOMClassInfo::nsDOMClassInfo(nsDOMClassInfoData* aData) : mData(aData) michael@0: { michael@0: } michael@0: michael@0: nsDOMClassInfo::~nsDOMClassInfo() michael@0: { michael@0: if (IS_EXTERNAL(mData->mCachedClassInfo)) { michael@0: // Some compilers don't like delete'ing a const nsDOMClassInfo* michael@0: nsDOMClassInfoData* data = const_cast(mData); michael@0: delete static_cast(data); michael@0: } michael@0: } michael@0: michael@0: NS_IMPL_ADDREF(nsDOMClassInfo) michael@0: NS_IMPL_RELEASE(nsDOMClassInfo) michael@0: michael@0: NS_INTERFACE_MAP_BEGIN(nsDOMClassInfo) michael@0: if (aIID.Equals(NS_GET_IID(nsXPCClassInfo))) michael@0: foundInterface = static_cast( michael@0: static_cast(this)); michael@0: else michael@0: NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) michael@0: NS_INTERFACE_MAP_ENTRY(nsIClassInfo) michael@0: NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIClassInfo) michael@0: NS_INTERFACE_MAP_END michael@0: michael@0: michael@0: static const JSClass sDOMConstructorProtoClass = { michael@0: "DOM Constructor.prototype", 0, michael@0: JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, michael@0: JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, nullptr michael@0: }; michael@0: michael@0: michael@0: static const char * michael@0: CutPrefix(const char *aName) { michael@0: static const char prefix_nsIDOM[] = "nsIDOM"; michael@0: static const char prefix_nsI[] = "nsI"; michael@0: michael@0: if (strncmp(aName, prefix_nsIDOM, sizeof(prefix_nsIDOM) - 1) == 0) { michael@0: return aName + sizeof(prefix_nsIDOM) - 1; michael@0: } michael@0: michael@0: if (strncmp(aName, prefix_nsI, sizeof(prefix_nsI) - 1) == 0) { michael@0: return aName + sizeof(prefix_nsI) - 1; michael@0: } michael@0: michael@0: return aName; michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: nsDOMClassInfo::RegisterClassProtos(int32_t aClassInfoID) michael@0: { michael@0: nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager(); michael@0: NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED); michael@0: bool found_old; michael@0: michael@0: const nsIID *primary_iid = sClassInfoData[aClassInfoID].mProtoChainInterface; michael@0: michael@0: if (!primary_iid || primary_iid == &NS_GET_IID(nsISupports)) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsCOMPtr michael@0: iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); michael@0: NS_ENSURE_TRUE(iim, NS_ERROR_NOT_AVAILABLE); michael@0: michael@0: nsCOMPtr if_info; michael@0: bool first = true; michael@0: michael@0: iim->GetInfoForIID(primary_iid, getter_AddRefs(if_info)); michael@0: michael@0: while (if_info) { michael@0: const nsIID *iid = nullptr; michael@0: michael@0: if_info->GetIIDShared(&iid); michael@0: NS_ENSURE_TRUE(iid, NS_ERROR_UNEXPECTED); michael@0: michael@0: if (iid->Equals(NS_GET_IID(nsISupports))) { michael@0: break; michael@0: } michael@0: michael@0: const char *name = nullptr; michael@0: if_info->GetNameShared(&name); michael@0: NS_ENSURE_TRUE(name, NS_ERROR_UNEXPECTED); michael@0: michael@0: nameSpaceManager->RegisterClassProto(CutPrefix(name), iid, &found_old); michael@0: michael@0: if (first) { michael@0: first = false; michael@0: } else if (found_old) { michael@0: break; michael@0: } michael@0: michael@0: nsCOMPtr tmp(if_info); michael@0: tmp->GetParent(getter_AddRefs(if_info)); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: nsDOMClassInfo::RegisterExternalClasses() michael@0: { michael@0: nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager(); michael@0: NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED); michael@0: michael@0: nsCOMPtr registrar; michael@0: nsresult rv = NS_GetComponentRegistrar(getter_AddRefs(registrar)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsCOMPtr cm = michael@0: do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsCOMPtr e; michael@0: rv = cm->EnumerateCategory(JAVASCRIPT_DOM_CLASS, getter_AddRefs(e)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsXPIDLCString contractId; michael@0: nsAutoCString categoryEntry; michael@0: nsCOMPtr entry; michael@0: michael@0: while (NS_SUCCEEDED(e->GetNext(getter_AddRefs(entry)))) { michael@0: nsCOMPtr category(do_QueryInterface(entry)); michael@0: michael@0: if (!category) { michael@0: NS_WARNING("Category entry not an nsISupportsCString!"); michael@0: continue; michael@0: } michael@0: michael@0: rv = category->GetData(categoryEntry); michael@0: michael@0: cm->GetCategoryEntry(JAVASCRIPT_DOM_CLASS, categoryEntry.get(), michael@0: getter_Copies(contractId)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsCID *cid; michael@0: rv = registrar->ContractIDToCID(contractId, &cid); michael@0: if (NS_FAILED(rv)) { michael@0: NS_WARNING("Bad contract id registered with the script namespace manager"); michael@0: continue; michael@0: } michael@0: michael@0: rv = nameSpaceManager->RegisterExternalClassName(categoryEntry.get(), *cid); michael@0: nsMemory::Free(cid); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } michael@0: michael@0: return nameSpaceManager->RegisterExternalInterfaces(true); michael@0: } michael@0: michael@0: #define _DOM_CLASSINFO_MAP_BEGIN(_class, _ifptr, _has_class_if) \ michael@0: { \ michael@0: nsDOMClassInfoData &d = sClassInfoData[eDOMClassInfo_##_class##_id]; \ michael@0: d.mProtoChainInterface = _ifptr; \ michael@0: d.mHasClassInterface = _has_class_if; \ michael@0: d.mInterfacesBitmap = kDOMClassInfo_##_class##_interfaces; \ michael@0: static const nsIID *interface_list[] = { michael@0: michael@0: #define DOM_CLASSINFO_MAP_BEGIN(_class, _interface) \ michael@0: _DOM_CLASSINFO_MAP_BEGIN(_class, &NS_GET_IID(_interface), true) michael@0: michael@0: #define DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(_class, _interface) \ michael@0: _DOM_CLASSINFO_MAP_BEGIN(_class, &NS_GET_IID(_interface), false) michael@0: michael@0: #define DOM_CLASSINFO_MAP_ENTRY(_if) \ michael@0: &NS_GET_IID(_if), michael@0: michael@0: #define DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(_if, _cond) \ michael@0: (_cond) ? &NS_GET_IID(_if) : nullptr, michael@0: michael@0: #define DOM_CLASSINFO_MAP_END \ michael@0: nullptr \ michael@0: }; \ michael@0: \ michael@0: /* Compact the interface list */ \ michael@0: size_t count = ArrayLength(interface_list); \ michael@0: /* count is the number of array entries, which is one greater than the */ \ michael@0: /* number of interfaces due to the terminating null */ \ michael@0: for (size_t i = 0; i < count - 1; ++i) { \ michael@0: if (!interface_list[i]) { \ michael@0: /* We are moving the element at index i+1 and successors, */ \ michael@0: /* so we must move only count - (i+1) elements total. */ \ michael@0: memmove(&interface_list[i], &interface_list[i+1], \ michael@0: sizeof(nsIID*) * (count - (i+1))); \ michael@0: /* Make sure to examine the new pointer we ended up with at this */ \ michael@0: /* slot, since it may be null too */ \ michael@0: --i; \ michael@0: --count; \ michael@0: } \ michael@0: } \ michael@0: \ michael@0: d.mInterfaces = interface_list; \ michael@0: } michael@0: michael@0: #ifdef MOZ_B2G michael@0: #define DOM_CLASSINFO_WINDOW_MAP_ENTRIES \ michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMWindow) \ michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMWindowB2G) \ michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMJSWindow) \ michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) \ michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers) \ michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMWindowPerformance) \ michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIInterfaceRequestor) \ michael@0: DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsITouchEventReceiver, \ michael@0: TouchEvent::PrefEnabled()) michael@0: #else // !MOZ_B2G michael@0: #define DOM_CLASSINFO_WINDOW_MAP_ENTRIES \ michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMWindow) \ michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMJSWindow) \ michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) \ michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers) \ michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMWindowPerformance) \ michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIInterfaceRequestor) \ michael@0: DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsITouchEventReceiver, \ michael@0: TouchEvent::PrefEnabled()) michael@0: #endif // MOZ_B2G michael@0: michael@0: nsresult michael@0: nsDOMClassInfo::Init() michael@0: { michael@0: /* Errors that can trigger early returns are done first, michael@0: otherwise nsDOMClassInfo is left in a half inited state. */ michael@0: static_assert(sizeof(uintptr_t) == sizeof(void*), michael@0: "BAD! You'll need to adjust the size of uintptr_t to the " michael@0: "size of a pointer on your platform."); michael@0: michael@0: NS_ENSURE_TRUE(!sIsInitialized, NS_ERROR_ALREADY_INITIALIZED); michael@0: michael@0: nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager(); michael@0: NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED); michael@0: michael@0: nsresult rv = CallGetService(nsIXPConnect::GetCID(), &sXPConnect); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsCOMPtr elt = new nsEventListenerThisTranslator(); michael@0: sXPConnect->SetFunctionThisTranslator(NS_GET_IID(nsIDOMEventListener), elt); michael@0: michael@0: nsCOMPtr sm = michael@0: do_GetService("@mozilla.org/scriptsecuritymanager;1", &rv); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: sSecMan = sm; michael@0: NS_ADDREF(sSecMan); michael@0: michael@0: AutoSafeJSContext cx; michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(Window, nsIDOMWindow) michael@0: DOM_CLASSINFO_WINDOW_MAP_ENTRIES michael@0: #ifdef MOZ_WEBSPEECH michael@0: DOM_CLASSINFO_MAP_ENTRY(nsISpeechSynthesisGetter) michael@0: #endif michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(WindowUtils, nsIDOMWindowUtils) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMWindowUtils) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(Location, nsIDOMLocation) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMLocation) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(DOMPrototype, nsIDOMDOMConstructor) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMConstructor) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(DOMConstructor, nsIDOMDOMConstructor) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMConstructor) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(CSSStyleRule, nsIDOMCSSStyleRule) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSStyleRule) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(CSSCharsetRule, nsIDOMCSSCharsetRule) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSCharsetRule) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(CSSImportRule, nsIDOMCSSImportRule) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSImportRule) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(CSSMediaRule, nsIDOMCSSMediaRule) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSMediaRule) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(CSSNameSpaceRule, nsIDOMCSSRule) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSRule) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(CSSRuleList, nsIDOMCSSRuleList) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSRuleList) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(CSSStyleSheet, nsIDOMCSSStyleSheet) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSStyleSheet) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: #ifdef MOZ_XUL michael@0: DOM_CLASSINFO_MAP_BEGIN(XULCommandDispatcher, nsIDOMXULCommandDispatcher) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULCommandDispatcher) michael@0: DOM_CLASSINFO_MAP_END michael@0: #endif michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULControllers, nsIControllers) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIControllers) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(BoxObject, nsIBoxObject) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIBoxObject) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: #ifdef MOZ_XUL michael@0: DOM_CLASSINFO_MAP_BEGIN(TreeSelection, nsITreeSelection) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsITreeSelection) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(TreeContentView, nsITreeContentView) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsITreeContentView) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsITreeView) michael@0: DOM_CLASSINFO_MAP_END michael@0: #endif michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ChromeWindow, nsIDOMWindow) michael@0: DOM_CLASSINFO_WINDOW_MAP_ENTRIES michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMChromeWindow) michael@0: #ifdef MOZ_WEBSPEECH michael@0: DOM_CLASSINFO_MAP_ENTRY(nsISpeechSynthesisGetter) michael@0: #endif michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: #ifdef MOZ_XUL michael@0: DOM_CLASSINFO_MAP_BEGIN(XULTemplateBuilder, nsIXULTemplateBuilder) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIXULTemplateBuilder) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(XULTreeBuilder, nsIXULTreeBuilder) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIXULTreeBuilder) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIXULTemplateBuilder) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsITreeView) michael@0: DOM_CLASSINFO_MAP_END michael@0: #endif michael@0: michael@0: #ifdef MOZ_XUL michael@0: DOM_CLASSINFO_MAP_BEGIN(TreeColumn, nsITreeColumn) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsITreeColumn) michael@0: DOM_CLASSINFO_MAP_END michael@0: #endif michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(CSSMozDocumentRule, nsIDOMCSSMozDocumentRule) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSMozDocumentRule) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(CSSSupportsRule, nsIDOMCSSSupportsRule) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSSupportsRule) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: // The SVG document michael@0: michael@0: // other SVG classes michael@0: DOM_CLASSINFO_MAP_BEGIN(SVGNumber, nsIDOMSVGNumber) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGNumber) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(XSLTProcessor, nsIXSLTProcessor) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIXSLTProcessor) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIXSLTProcessorPrivate) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(XPathExpression, nsIDOMXPathExpression) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMXPathExpression) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSXPathExpression) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(XPathNSResolver, nsIDOMXPathNSResolver) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMXPathNSResolver) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(XPathResult, nsIDOMXPathResult) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMXPathResult) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(Storage, nsIDOMStorage) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorage) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(Blob, nsIDOMBlob) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMBlob) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(File, nsIDOMFile) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMBlob) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMFile) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ModalContentWindow, nsIDOMWindow) michael@0: DOM_CLASSINFO_WINDOW_MAP_ENTRIES michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMModalContentWindow) michael@0: #ifdef MOZ_WEBSPEECH michael@0: DOM_CLASSINFO_MAP_ENTRY(nsISpeechSynthesisGetter) michael@0: #endif michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(MozMobileMessageManager, nsIDOMMozMobileMessageManager) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozMobileMessageManager) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(MozSmsMessage, nsIDOMMozSmsMessage) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozSmsMessage) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(MozMmsMessage, nsIDOMMozMmsMessage) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozMmsMessage) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(MozSmsFilter, nsIDOMMozSmsFilter) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozSmsFilter) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(MozSmsSegmentInfo, nsIDOMMozSmsSegmentInfo) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozSmsSegmentInfo) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(MozMobileMessageThread, nsIDOMMozMobileMessageThread) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozMobileMessageThread) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: #ifdef MOZ_B2G_RIL michael@0: DOM_CLASSINFO_MAP_BEGIN(MozMobileConnection, nsIDOMMozMobileConnection) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozMobileConnection) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) michael@0: DOM_CLASSINFO_MAP_END michael@0: #endif // MOZ_B2G_RIL michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(CSSFontFaceRule, nsIDOMCSSFontFaceRule) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSFontFaceRule) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ContentFrameMessageManager, nsISupports) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIMessageSender) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsISyncMessageSender) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIContentFrameMessageManager) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ChromeMessageBroadcaster, nsISupports) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIFrameScriptLoader) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIMessageBroadcaster) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ChromeMessageSender, nsISupports) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIProcessChecker) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIFrameScriptLoader) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIMessageSender) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(MozCSSKeyframeRule, nsIDOMMozCSSKeyframeRule) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozCSSKeyframeRule) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(MozCSSKeyframesRule, nsIDOMMozCSSKeyframesRule) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozCSSKeyframesRule) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(CSSPageRule, nsIDOMCSSPageRule) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSPageRule) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN(CSSFontFeatureValuesRule, nsIDOMCSSFontFeatureValuesRule) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSFontFeatureValuesRule) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(UserDataHandler, nsIDOMUserDataHandler) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMUserDataHandler) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULControlElement, nsIDOMXULControlElement) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULControlElement) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULLabeledControlElement, nsIDOMXULLabeledControlElement) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULLabeledControlElement) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULButtonElement, nsIDOMXULButtonElement) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULButtonElement) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULCheckboxElement, nsIDOMXULCheckboxElement) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULCheckboxElement) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULPopupElement, nsIDOMXULPopupElement) michael@0: DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULPopupElement) michael@0: DOM_CLASSINFO_MAP_END michael@0: michael@0: static_assert(MOZ_ARRAY_LENGTH(sClassInfoData) == eDOMClassInfoIDCount, michael@0: "The number of items in sClassInfoData doesn't match the " michael@0: "number of nsIDOMClassInfo ID's, this is bad! Fix it!"); michael@0: michael@0: #ifdef DEBUG michael@0: for (size_t i = 0; i < eDOMClassInfoIDCount; i++) { michael@0: if (!sClassInfoData[i].u.mConstructorFptr || michael@0: sClassInfoData[i].mDebugID != i) { michael@0: MOZ_CRASH("Class info data out of sync, you forgot to update " michael@0: "nsDOMClassInfo.h and nsDOMClassInfo.cpp! Fix this, " michael@0: "mozilla will not work without this fixed!"); michael@0: } michael@0: } michael@0: michael@0: for (size_t i = 0; i < eDOMClassInfoIDCount; i++) { michael@0: if (!sClassInfoData[i].mInterfaces) { michael@0: MOZ_CRASH("Class info data without an interface list! Fix this, " michael@0: "mozilla will not work without this fixed!"); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: // Initialize static JSString's michael@0: DefineStaticJSVals(cx); michael@0: michael@0: int32_t i; michael@0: michael@0: for (i = 0; i < eDOMClassInfoIDCount; ++i) { michael@0: if (i == eDOMClassInfo_DOMPrototype_id) { michael@0: continue; michael@0: } michael@0: michael@0: nsDOMClassInfoData& data = sClassInfoData[i]; michael@0: nameSpaceManager->RegisterClassName(data.mName, i, data.mChromeOnly, michael@0: data.mAllowXBL, &data.mNameUTF16); michael@0: } michael@0: michael@0: for (i = 0; i < eDOMClassInfoIDCount; ++i) { michael@0: RegisterClassProtos(i); michael@0: } michael@0: michael@0: RegisterExternalClasses(); michael@0: michael@0: // Register new DOM bindings michael@0: mozilla::dom::Register(nameSpaceManager); michael@0: michael@0: sIsInitialized = true; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // static michael@0: int32_t michael@0: nsDOMClassInfo::GetArrayIndexFromId(JSContext *cx, JS::Handle id, bool *aIsNumber) michael@0: { michael@0: if (aIsNumber) { michael@0: *aIsNumber = false; michael@0: } michael@0: michael@0: int i; michael@0: if (JSID_IS_INT(id)) { michael@0: i = JSID_TO_INT(id); michael@0: } else { michael@0: JS::Rooted idval(cx); michael@0: double array_index; michael@0: if (!::JS_IdToValue(cx, id, &idval) || michael@0: !JS::ToNumber(cx, idval, &array_index) || michael@0: !::JS_DoubleIsInt32(array_index, &i)) { michael@0: return -1; michael@0: } michael@0: } michael@0: michael@0: if (aIsNumber) { michael@0: *aIsNumber = true; michael@0: } michael@0: michael@0: return i; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::GetInterfaces(uint32_t *aCount, nsIID ***aArray) michael@0: { michael@0: uint32_t count = 0; michael@0: michael@0: while (mData->mInterfaces[count]) { michael@0: count++; michael@0: } michael@0: michael@0: *aCount = count; michael@0: michael@0: if (!count) { michael@0: *aArray = nullptr; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: *aArray = static_cast(nsMemory::Alloc(count * sizeof(nsIID *))); michael@0: NS_ENSURE_TRUE(*aArray, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: uint32_t i; michael@0: for (i = 0; i < count; i++) { michael@0: nsIID *iid = static_cast(nsMemory::Clone(mData->mInterfaces[i], michael@0: sizeof(nsIID))); michael@0: michael@0: if (!iid) { michael@0: NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, *aArray); michael@0: michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: *((*aArray) + i) = iid; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::GetHelperForLanguage(uint32_t language, nsISupports **_retval) michael@0: { michael@0: if (language == nsIProgrammingLanguage::JAVASCRIPT) { michael@0: *_retval = static_cast(this); michael@0: michael@0: NS_ADDREF(*_retval); michael@0: } else { michael@0: *_retval = nullptr; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::GetContractID(char **aContractID) michael@0: { michael@0: *aContractID = nullptr; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::GetClassDescription(char **aClassDescription) michael@0: { michael@0: return GetClassName(aClassDescription); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::GetClassID(nsCID **aClassID) michael@0: { michael@0: *aClassID = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::GetClassIDNoAlloc(nsCID *aClassID) michael@0: { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::GetImplementationLanguage(uint32_t *aImplLanguage) michael@0: { michael@0: *aImplLanguage = nsIProgrammingLanguage::CPLUSPLUS; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::GetFlags(uint32_t *aFlags) michael@0: { michael@0: *aFlags = DOMCLASSINFO_STANDARD_FLAGS; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // nsIXPCScriptable michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::GetClassName(char **aClassName) michael@0: { michael@0: *aClassName = NS_strdup(mData->mName); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // virtual michael@0: uint32_t michael@0: nsDOMClassInfo::GetScriptableFlags() michael@0: { michael@0: return mData->mScriptableFlags; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::PreCreate(nsISupports *nativeObj, JSContext *cx, michael@0: JSObject *globalObj, JSObject **parentObj) michael@0: { michael@0: *parentObj = globalObj; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::Create(nsIXPConnectWrappedNative *wrapper, michael@0: JSContext *cx, JSObject *obj) michael@0: { michael@0: NS_WARNING("nsDOMClassInfo::Create Don't call me!"); michael@0: michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::PostCreate(nsIXPConnectWrappedNative *wrapper, michael@0: JSContext *cx, JSObject *obj) michael@0: { michael@0: NS_WARNING("nsDOMClassInfo::PostCreate Don't call me!"); michael@0: michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::PostTransplant(nsIXPConnectWrappedNative *wrapper, michael@0: JSContext *cx, JSObject *obj) michael@0: { michael@0: MOZ_CRASH("nsDOMClassInfo::PostTransplant Don't call me!"); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, jsid id, jsval *vp, michael@0: bool *_retval) michael@0: { michael@0: NS_WARNING("nsDOMClassInfo::AddProperty Don't call me!"); michael@0: michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::DelProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, jsid id, bool *_retval) michael@0: { michael@0: NS_WARNING("nsDOMClassInfo::DelProperty Don't call me!"); michael@0: michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, jsid id, jsval *vp, michael@0: bool *_retval) michael@0: { michael@0: NS_WARNING("nsDOMClassInfo::GetProperty Don't call me!"); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, jsid id, jsval *vp, michael@0: bool *_retval) michael@0: { michael@0: NS_WARNING("nsDOMClassInfo::SetProperty Don't call me!"); michael@0: michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, bool *_retval) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::NewEnumerate(nsIXPConnectWrappedNative *wrapper, michael@0: JSContext *cx, JSObject *obj, uint32_t enum_op, michael@0: jsval *statep, jsid *idp, bool *_retval) michael@0: { michael@0: NS_WARNING("nsDOMClassInfo::NewEnumerate Don't call me!"); michael@0: michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: nsresult michael@0: nsDOMClassInfo::ResolveConstructor(JSContext *cx, JSObject *aObj, michael@0: JSObject **objp) michael@0: { michael@0: JS::Rooted obj(cx, aObj); michael@0: JS::Rooted global(cx, ::JS_GetGlobalForObject(cx, obj)); michael@0: michael@0: JS::Rooted val(cx); michael@0: if (!::JS_LookupProperty(cx, global, mData->mName, &val)) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: if (!JSVAL_IS_PRIMITIVE(val)) { michael@0: // If val is not an (non-null) object there either is no michael@0: // constructor for this class, or someone messed with michael@0: // window.classname, just fall through and let the JS engine michael@0: // return the Object constructor. michael@0: michael@0: if (!::JS_DefinePropertyById(cx, obj, sConstructor_id, val, JS_PropertyStub, michael@0: JS_StrictPropertyStub, JSPROP_ENUMERATE)) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: *objp = obj; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, jsid id, JSObject **objp, michael@0: bool *_retval) michael@0: { michael@0: if (id == sConstructor_id) { michael@0: return ResolveConstructor(cx, obj, objp); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::Convert(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, uint32_t type, jsval *vp, michael@0: bool *_retval) michael@0: { michael@0: NS_WARNING("nsDOMClassInfo::Convert Don't call me!"); michael@0: michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::Finalize(nsIXPConnectWrappedNative *wrapper, JSFreeOp *fop, michael@0: JSObject *obj) michael@0: { michael@0: NS_WARNING("nsDOMClassInfo::Finalize Don't call me!"); michael@0: michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::Call(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, const JS::CallArgs &args, bool *_retval) michael@0: { michael@0: NS_WARNING("nsDOMClassInfo::Call Don't call me!"); michael@0: michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::Construct(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, const JS::CallArgs &args, michael@0: bool *_retval) michael@0: { michael@0: NS_WARNING("nsDOMClassInfo::Construct Don't call me!"); michael@0: michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::HasInstance(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, JS::Handle val, bool *bp, michael@0: bool *_retval) michael@0: { michael@0: NS_WARNING("nsDOMClassInfo::HasInstance Don't call me!"); michael@0: michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx, michael@0: JSObject * obj, JSObject * *_retval) michael@0: { michael@0: NS_WARNING("nsDOMClassInfo::OuterObject Don't call me!"); michael@0: michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: static nsresult michael@0: GetExternalClassInfo(nsScriptNameSpaceManager *aNameSpaceManager, michael@0: const nsAString &aName, michael@0: const nsGlobalNameStruct *aStruct, michael@0: const nsGlobalNameStruct **aResult) michael@0: { michael@0: NS_ASSERTION(aStruct->mType == michael@0: nsGlobalNameStruct::eTypeExternalClassInfoCreator, michael@0: "Wrong type!"); michael@0: michael@0: nsresult rv; michael@0: nsCOMPtr creator(do_CreateInstance(aStruct->mCID, &rv)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsCOMPtr sof(do_GetService(kDOMSOF_CID)); michael@0: NS_ENSURE_TRUE(sof, NS_ERROR_FAILURE); michael@0: michael@0: rv = creator->RegisterDOMCI(NS_ConvertUTF16toUTF8(aName).get(), sof); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: const nsGlobalNameStruct *name_struct = aNameSpaceManager->LookupName(aName); michael@0: if (name_struct && michael@0: name_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfo) { michael@0: *aResult = name_struct; michael@0: } michael@0: else { michael@0: NS_ERROR("Couldn't get the DOM ClassInfo data."); michael@0: michael@0: *aResult = nullptr; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: static nsresult michael@0: ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx, michael@0: JS::Handle obj, const char16_t *name, michael@0: const nsDOMClassInfoData *ci_data, michael@0: const nsGlobalNameStruct *name_struct, michael@0: nsScriptNameSpaceManager *nameSpaceManager, michael@0: JSObject *dot_prototype, michael@0: JS::MutableHandle ctorDesc); michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMClassInfo::PostCreatePrototype(JSContext * cx, JSObject * aProto) michael@0: { michael@0: uint32_t flags = (mData->mScriptableFlags & DONT_ENUM_STATIC_PROPS) michael@0: ? 0 michael@0: : JSPROP_ENUMERATE; michael@0: michael@0: uint32_t count = 0; michael@0: while (mData->mInterfaces[count]) { michael@0: count++; michael@0: } michael@0: michael@0: JS::Rooted proto(cx, aProto); michael@0: if (!xpc::DOM_DefineQuickStubs(cx, proto, flags, count, mData->mInterfaces)) { michael@0: JS_ClearPendingException(cx); michael@0: } michael@0: michael@0: // This is called before any other location that requires michael@0: // sObjectClass, so compute it here. We assume that nobody has had a michael@0: // chance to monkey around with proto's prototype chain before this. michael@0: if (!sObjectClass) { michael@0: FindObjectClass(cx, proto); michael@0: NS_ASSERTION(sObjectClass && !strcmp(sObjectClass->name, "Object"), michael@0: "Incorrect object class!"); michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: JS::Rooted proto2(cx); michael@0: JS_GetPrototype(cx, proto, &proto2); michael@0: NS_ASSERTION(proto2 && JS_GetClass(proto2) == sObjectClass, michael@0: "Hmm, somebody did something evil?"); michael@0: #endif michael@0: michael@0: #ifdef DEBUG michael@0: if (mData->mHasClassInterface && mData->mProtoChainInterface && michael@0: mData->mProtoChainInterface != &NS_GET_IID(nsISupports)) { michael@0: nsCOMPtr michael@0: iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); michael@0: michael@0: if (iim) { michael@0: nsCOMPtr if_info; michael@0: iim->GetInfoForIID(mData->mProtoChainInterface, michael@0: getter_AddRefs(if_info)); michael@0: michael@0: if (if_info) { michael@0: nsXPIDLCString name; michael@0: if_info->GetName(getter_Copies(name)); michael@0: NS_ASSERTION(nsCRT::strcmp(CutPrefix(name), mData->mName) == 0, michael@0: "Class name and proto chain interface name mismatch!"); michael@0: } michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: // Make prototype delegation work correctly. Consider if a site sets michael@0: // HTMLElement.prototype.foopy = function () { ... } Now, calling michael@0: // document.body.foopy() needs to ensure that looking up foopy on michael@0: // document.body's prototype will find the right function. michael@0: JS::Rooted global(cx, ::JS_GetGlobalForObject(cx, proto)); michael@0: michael@0: // Only do this if the global object is a window. michael@0: // XXX Is there a better way to check this? michael@0: nsISupports *globalNative = XPConnect()->GetNativeOfWrapper(cx, global); michael@0: nsCOMPtr piwin = do_QueryInterface(globalNative); michael@0: if (!piwin) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsGlobalWindow *win = nsGlobalWindow::FromSupports(globalNative); michael@0: if (win->IsClosedOrClosing()) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: // If the window is in a different compartment than the global object, then michael@0: // it's likely that global is a sandbox object whose prototype is a window. michael@0: // Don't do anything in this case. michael@0: if (win->FastGetGlobalJSObject() && michael@0: js::GetObjectCompartment(global) != js::GetObjectCompartment(win->FastGetGlobalJSObject())) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (win->IsOuterWindow()) { michael@0: // XXXjst: Do security checks here when we remove the security michael@0: // checks on the inner window. michael@0: michael@0: win = win->GetCurrentInnerWindowInternal(); michael@0: michael@0: if (!win || !(global = win->GetGlobalJSObject()) || michael@0: win->IsClosedOrClosing()) { michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: // Don't overwrite a property set by content. michael@0: bool contentDefinedProperty; michael@0: if (!::JS_AlreadyHasOwnUCProperty(cx, global, reinterpret_cast(mData->mNameUTF16), michael@0: NS_strlen(mData->mNameUTF16), michael@0: &contentDefinedProperty)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager(); michael@0: NS_ENSURE_TRUE(nameSpaceManager, NS_OK); michael@0: michael@0: JS::Rooted desc(cx); michael@0: nsresult rv = ResolvePrototype(sXPConnect, win, cx, global, mData->mNameUTF16, michael@0: mData, nullptr, nameSpaceManager, proto, michael@0: &desc); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: if (!contentDefinedProperty && desc.object() && !desc.value().isUndefined() && michael@0: !JS_DefineUCProperty(cx, global, mData->mNameUTF16, michael@0: NS_strlen(mData->mNameUTF16), michael@0: desc.value(), desc.getter(), desc.setter(), michael@0: desc.attributes())) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // static michael@0: nsIClassInfo * michael@0: NS_GetDOMClassInfoInstance(nsDOMClassInfoID aID) michael@0: { michael@0: if (aID >= eDOMClassInfoIDCount) { michael@0: NS_ERROR("Bad ID!"); michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: if (!nsDOMClassInfo::sIsInitialized) { michael@0: nsresult rv = nsDOMClassInfo::Init(); michael@0: michael@0: NS_ENSURE_SUCCESS(rv, nullptr); michael@0: } michael@0: michael@0: if (!sClassInfoData[aID].mCachedClassInfo) { michael@0: nsDOMClassInfoData& data = sClassInfoData[aID]; michael@0: michael@0: data.mCachedClassInfo = data.u.mConstructorFptr(&data); michael@0: NS_ENSURE_TRUE(data.mCachedClassInfo, nullptr); michael@0: michael@0: NS_ADDREF(data.mCachedClassInfo); michael@0: } michael@0: michael@0: NS_ASSERTION(!IS_EXTERNAL(sClassInfoData[aID].mCachedClassInfo), michael@0: "This is bad, internal class marked as external!"); michael@0: michael@0: return sClassInfoData[aID].mCachedClassInfo; michael@0: } michael@0: michael@0: // static michael@0: nsIClassInfo * michael@0: nsDOMClassInfo::GetClassInfoInstance(nsDOMClassInfoData* aData) michael@0: { michael@0: NS_ASSERTION(IS_EXTERNAL(aData->mCachedClassInfo) michael@0: || !aData->mCachedClassInfo, michael@0: "This is bad, external class marked as internal!"); michael@0: michael@0: if (!aData->mCachedClassInfo) { michael@0: if (aData->u.mExternalConstructorFptr) { michael@0: aData->mCachedClassInfo = michael@0: aData->u.mExternalConstructorFptr(aData->mName); michael@0: } else { michael@0: aData->mCachedClassInfo = nsDOMGenericSH::doCreate(aData); michael@0: } michael@0: NS_ENSURE_TRUE(aData->mCachedClassInfo, nullptr); michael@0: michael@0: NS_ADDREF(aData->mCachedClassInfo); michael@0: aData->mCachedClassInfo = MARK_EXTERNAL(aData->mCachedClassInfo); michael@0: } michael@0: michael@0: return GET_CLEAN_CI_PTR(aData->mCachedClassInfo); michael@0: } michael@0: michael@0: michael@0: // static michael@0: void michael@0: nsDOMClassInfo::ShutDown() michael@0: { michael@0: if (sClassInfoData[0].u.mConstructorFptr) { michael@0: uint32_t i; michael@0: michael@0: for (i = 0; i < eDOMClassInfoIDCount; i++) { michael@0: NS_IF_RELEASE(sClassInfoData[i].mCachedClassInfo); michael@0: } michael@0: } michael@0: michael@0: sLocation_id = JSID_VOID; michael@0: sConstructor_id = JSID_VOID; michael@0: sLength_id = JSID_VOID; michael@0: sItem_id = JSID_VOID; michael@0: sEnumerate_id = JSID_VOID; michael@0: sTop_id = JSID_VOID; michael@0: sDocument_id = JSID_VOID; michael@0: sWrappedJSObject_id = JSID_VOID; michael@0: michael@0: NS_IF_RELEASE(sXPConnect); michael@0: NS_IF_RELEASE(sSecMan); michael@0: sIsInitialized = false; michael@0: } michael@0: michael@0: // Window helper michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindowSH::PreCreate(nsISupports *nativeObj, JSContext *cx, michael@0: JSObject *globalObj, JSObject **parentObj) michael@0: { michael@0: // Normally ::PreCreate() is used to give XPConnect the parent michael@0: // object for the object that's being wrapped, this parent object is michael@0: // set as the parent of the wrapper and it's also used to find the michael@0: // right scope for the object being wrapped. Now, in the case of the michael@0: // global object the wrapper shouldn't have a parent but we supply michael@0: // one here anyway (the global object itself) and this will be used michael@0: // by XPConnect only to find the right scope, once the scope is michael@0: // found XPConnect will find the existing wrapper (which always michael@0: // exists since it's created on window construction), since an michael@0: // existing wrapper is found the parent we supply here is ignored michael@0: // after the wrapper is found. michael@0: michael@0: nsCOMPtr sgo(do_QueryInterface(nativeObj)); michael@0: NS_ASSERTION(sgo, "nativeObj not a global object!"); michael@0: michael@0: nsGlobalWindow *win = nsGlobalWindow::FromSupports(nativeObj); michael@0: NS_ASSERTION(win->IsInnerWindow(), "Should be inner window."); michael@0: michael@0: // We sometimes get a disconnected window during file api test. :-( michael@0: if (!win->GetOuterWindowInternal()) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: // If we're bootstrapping, we don't have a JS object yet. michael@0: if (win->GetOuterWindowInternal()->IsCreatingInnerWindow()) michael@0: return NS_OK; michael@0: michael@0: return SetParentToWindow(win, parentObj); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindowSH::PostCreatePrototype(JSContext* aCx, JSObject* aProto) michael@0: { michael@0: JS::Rooted proto(aCx, aProto); michael@0: michael@0: nsresult rv = nsDOMClassInfo::PostCreatePrototype(aCx, proto); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // We should probably move this into the CreateInterfaceObjects for Window michael@0: // once it is on WebIDL bindings. michael@0: WindowNamedPropertiesHandler::Install(aCx, proto); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindowSH::PostCreate(nsIXPConnectWrappedNative *wrapper, michael@0: JSContext *cx, JSObject *obj) michael@0: { michael@0: JS::Rooted window(cx, obj); michael@0: michael@0: #ifdef DEBUG michael@0: nsCOMPtr sgo(do_QueryWrappedNative(wrapper)); michael@0: michael@0: NS_ASSERTION(sgo && sgo->GetGlobalJSObject() == obj, michael@0: "Multiple wrappers created for global object!"); michael@0: #endif michael@0: michael@0: const NativeProperties* windowProperties = michael@0: WindowBinding::sNativePropertyHooks->mNativeProperties.regular; michael@0: const NativeProperties* eventTargetProperties = michael@0: EventTargetBinding::sNativePropertyHooks->mNativeProperties.regular; michael@0: michael@0: return DefineWebIDLBindingPropertiesOnXPCObject(cx, window, windowProperties, true) && michael@0: DefineWebIDLBindingPropertiesOnXPCObject(cx, window, eventTargetProperties, true) ? michael@0: NS_OK : NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: struct ResolveGlobalNameClosure michael@0: { michael@0: JSContext* cx; michael@0: JS::Handle obj; michael@0: bool* retval; michael@0: }; michael@0: michael@0: static PLDHashOperator michael@0: ResolveGlobalName(const nsAString& aName, michael@0: const nsGlobalNameStruct& aNameStruct, michael@0: void* aClosure) michael@0: { michael@0: ResolveGlobalNameClosure* closure = michael@0: static_cast(aClosure); michael@0: JS::Rooted dummy(closure->cx); michael@0: bool ok = JS_LookupUCProperty(closure->cx, closure->obj, michael@0: aName.BeginReading(), aName.Length(), michael@0: &dummy); michael@0: if (!ok) { michael@0: *closure->retval = false; michael@0: return PL_DHASH_STOP; michael@0: } michael@0: return PL_DHASH_NEXT; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindowSH::Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *aObj, bool *_retval) michael@0: { michael@0: JS::Rooted obj(cx, aObj); michael@0: if (!xpc::WrapperFactory::IsXrayWrapper(obj)) { michael@0: *_retval = JS_EnumerateStandardClasses(cx, obj); michael@0: if (!*_retval) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Now resolve everything from the namespace manager michael@0: nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager(); michael@0: if (!nameSpaceManager) { michael@0: NS_ERROR("Can't get namespace manager."); michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: ResolveGlobalNameClosure closure = { cx, obj, _retval }; michael@0: nameSpaceManager->EnumerateGlobalNames(ResolveGlobalName, &closure); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsDOMConstructorFunc michael@0: FindConstructorFunc(const nsDOMClassInfoData *aDOMClassInfoData) michael@0: { michael@0: for (uint32_t i = 0; i < ArrayLength(kConstructorFuncMap); ++i) { michael@0: if (&sClassInfoData[kConstructorFuncMap[i].mDOMClassInfoID] == michael@0: aDOMClassInfoData) { michael@0: return kConstructorFuncMap[i].mConstructorFunc; michael@0: } michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: static nsresult michael@0: BaseStubConstructor(nsIWeakReference* aWeakOwner, michael@0: const nsGlobalNameStruct *name_struct, JSContext *cx, michael@0: JS::Handle obj, const JS::CallArgs &args) michael@0: { michael@0: MOZ_ASSERT(obj); michael@0: michael@0: nsresult rv; michael@0: nsCOMPtr native; michael@0: if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) { michael@0: const nsDOMClassInfoData* ci_data = michael@0: &sClassInfoData[name_struct->mDOMClassInfoID]; michael@0: nsDOMConstructorFunc func = FindConstructorFunc(ci_data); michael@0: if (func) { michael@0: rv = func(getter_AddRefs(native)); michael@0: } else { michael@0: rv = NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: } else if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructor) { michael@0: native = do_CreateInstance(name_struct->mCID, &rv); michael@0: } else if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias) { michael@0: native = do_CreateInstance(name_struct->mAlias->mCID, &rv); michael@0: } else { michael@0: native = do_CreateInstance(*name_struct->mData->mConstructorCID, &rv); michael@0: } michael@0: if (NS_FAILED(rv)) { michael@0: NS_ERROR("Failed to create the object"); michael@0: return rv; michael@0: } michael@0: michael@0: nsCOMPtr initializer(do_QueryInterface(native)); michael@0: nsCOMPtr constructor(do_QueryInterface(native)); michael@0: if (initializer || constructor) { michael@0: // Initialize object using the current inner window, but only if michael@0: // the caller can access it. michael@0: nsCOMPtr owner = do_QueryReferent(aWeakOwner); michael@0: nsPIDOMWindow* outerWindow = owner ? owner->GetOuterWindow() : nullptr; michael@0: nsPIDOMWindow* currentInner = michael@0: outerWindow ? outerWindow->GetCurrentInnerWindow() : nullptr; michael@0: if (!currentInner || michael@0: (owner != currentInner && michael@0: !nsContentUtils::CanCallerAccess(currentInner))) { michael@0: return NS_ERROR_DOM_SECURITY_ERR; michael@0: } michael@0: michael@0: if (initializer) { michael@0: rv = initializer->Initialize(currentInner, cx, obj, args); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: } else { michael@0: nsCOMPtr wrappedJS = do_QueryInterface(native); michael@0: michael@0: JS::Rooted thisObject(cx, wrappedJS->GetJSObject()); michael@0: if (!thisObject) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: nsCxPusher pusher; michael@0: pusher.Push(cx); michael@0: michael@0: JSAutoCompartment ac(cx, thisObject); michael@0: michael@0: JS::Rooted funval(cx); michael@0: if (!JS_GetProperty(cx, thisObject, "constructor", &funval) || michael@0: !funval.isObject()) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: // Check if the object is even callable. michael@0: NS_ENSURE_STATE(JS_ObjectIsCallable(cx, &funval.toObject())); michael@0: { michael@0: // wrap parameters in the target compartment michael@0: // we also pass in the calling window as the first argument michael@0: unsigned argc = args.length() + 1; michael@0: JS::AutoValueVector argv(cx); michael@0: if (!argv.resize(argc)) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: nsCOMPtr currentWin(do_GetInterface(currentInner)); michael@0: rv = WrapNative(cx, currentWin, &NS_GET_IID(nsIDOMWindow), michael@0: true, argv.handleAt(0)); michael@0: michael@0: for (size_t i = 1; i < argc; ++i) { michael@0: argv[i] = args[i - 1]; michael@0: if (!JS_WrapValue(cx, argv.handleAt(i))) michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: JS::Rooted frval(cx); michael@0: bool ret = JS_CallFunctionValue(cx, thisObject, funval, argv, &frval); michael@0: michael@0: if (!ret) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: js::AssertSameCompartment(cx, obj); michael@0: return WrapNative(cx, native, true, args.rval()); michael@0: } michael@0: michael@0: static nsresult michael@0: DefineInterfaceConstants(JSContext *cx, JS::Handle obj, const nsIID *aIID) michael@0: { michael@0: nsCOMPtr michael@0: iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); michael@0: NS_ENSURE_TRUE(iim, NS_ERROR_UNEXPECTED); michael@0: michael@0: nsCOMPtr if_info; michael@0: michael@0: nsresult rv = iim->GetInfoForIID(aIID, getter_AddRefs(if_info)); michael@0: NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && if_info, rv); michael@0: michael@0: uint16_t constant_count; michael@0: michael@0: if_info->GetConstantCount(&constant_count); michael@0: michael@0: if (!constant_count) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsCOMPtr parent_if_info; michael@0: michael@0: rv = if_info->GetParent(getter_AddRefs(parent_if_info)); michael@0: NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && parent_if_info, rv); michael@0: michael@0: uint16_t parent_constant_count, i; michael@0: parent_if_info->GetConstantCount(&parent_constant_count); michael@0: michael@0: JS::Rooted v(cx); michael@0: for (i = parent_constant_count; i < constant_count; i++) { michael@0: const nsXPTConstant *c = nullptr; michael@0: michael@0: rv = if_info->GetConstant(i, &c); michael@0: NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && c, rv); michael@0: michael@0: uint16_t type = c->GetType().TagPart(); michael@0: michael@0: v.setUndefined(); michael@0: switch (type) { michael@0: case nsXPTType::T_I8: michael@0: case nsXPTType::T_U8: michael@0: { michael@0: v.setInt32(c->GetValue()->val.u8); michael@0: break; michael@0: } michael@0: case nsXPTType::T_I16: michael@0: case nsXPTType::T_U16: michael@0: { michael@0: v.setInt32(c->GetValue()->val.u16); michael@0: break; michael@0: } michael@0: case nsXPTType::T_I32: michael@0: { michael@0: v = JS_NumberValue(c->GetValue()->val.i32); michael@0: break; michael@0: } michael@0: case nsXPTType::T_U32: michael@0: { michael@0: v = JS_NumberValue(c->GetValue()->val.u32); michael@0: break; michael@0: } michael@0: default: michael@0: { michael@0: #ifdef DEBUG michael@0: NS_ERROR("Non-numeric constant found in interface."); michael@0: #endif michael@0: continue; michael@0: } michael@0: } michael@0: michael@0: if (!::JS_DefineProperty(cx, obj, c->GetName(), v, michael@0: JSPROP_ENUMERATE | JSPROP_READONLY | michael@0: JSPROP_PERMANENT, michael@0: JS_PropertyStub, JS_StrictPropertyStub)) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: class nsDOMConstructor MOZ_FINAL : public nsIDOMDOMConstructor michael@0: { michael@0: protected: michael@0: nsDOMConstructor(const char16_t* aName, michael@0: bool aIsConstructable, michael@0: nsPIDOMWindow* aOwner) michael@0: : mClassName(aName), michael@0: mConstructable(aIsConstructable), michael@0: mWeakOwner(do_GetWeakReference(aOwner)) michael@0: { michael@0: } michael@0: michael@0: public: michael@0: michael@0: static nsresult Create(const char16_t* aName, michael@0: const nsDOMClassInfoData* aData, michael@0: const nsGlobalNameStruct* aNameStruct, michael@0: nsPIDOMWindow* aOwner, michael@0: nsDOMConstructor** aResult); michael@0: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIDOMDOMCONSTRUCTOR michael@0: michael@0: nsresult PreCreate(JSContext *cx, JSObject *globalObj, JSObject **parentObj); michael@0: michael@0: nsresult Construct(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JS::Handle obj, const JS::CallArgs &args, michael@0: bool *_retval); michael@0: michael@0: nsresult HasInstance(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JS::Handle obj, const jsval &val, bool *bp, michael@0: bool *_retval); michael@0: michael@0: nsresult ResolveInterfaceConstants(JSContext *cx, JS::Handle obj); michael@0: michael@0: private: michael@0: const nsGlobalNameStruct *GetNameStruct() michael@0: { michael@0: if (!mClassName) { michael@0: NS_ERROR("Can't get name"); michael@0: return nullptr; michael@0: } michael@0: michael@0: const nsGlobalNameStruct *nameStruct; michael@0: #ifdef DEBUG michael@0: nsresult rv = michael@0: #endif michael@0: GetNameStruct(nsDependentString(mClassName), &nameStruct); michael@0: michael@0: NS_ASSERTION(NS_FAILED(rv) || nameStruct, "Name isn't in hash."); michael@0: michael@0: return nameStruct; michael@0: } michael@0: michael@0: static nsresult GetNameStruct(const nsAString& aName, michael@0: const nsGlobalNameStruct **aNameStruct) michael@0: { michael@0: *aNameStruct = nullptr; michael@0: michael@0: nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager(); michael@0: if (!nameSpaceManager) { michael@0: NS_ERROR("Can't get namespace manager."); michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: *aNameStruct = nameSpaceManager->LookupName(aName); michael@0: michael@0: // Return NS_OK here, aName just isn't a DOM class but nothing failed. michael@0: return NS_OK; michael@0: } michael@0: michael@0: static bool IsConstructable(const nsDOMClassInfoData *aData) michael@0: { michael@0: if (IS_EXTERNAL(aData->mCachedClassInfo)) { michael@0: const nsExternalDOMClassInfoData* data = michael@0: static_cast(aData); michael@0: return data->mConstructorCID != nullptr; michael@0: } michael@0: michael@0: return FindConstructorFunc(aData); michael@0: } michael@0: static bool IsConstructable(const nsGlobalNameStruct *aNameStruct) michael@0: { michael@0: return michael@0: (aNameStruct->mType == nsGlobalNameStruct::eTypeClassConstructor && michael@0: IsConstructable(&sClassInfoData[aNameStruct->mDOMClassInfoID])) || michael@0: (aNameStruct->mType == nsGlobalNameStruct::eTypeExternalClassInfo && michael@0: IsConstructable(aNameStruct->mData)) || michael@0: aNameStruct->mType == nsGlobalNameStruct::eTypeExternalConstructor || michael@0: aNameStruct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias; michael@0: } michael@0: michael@0: const char16_t* mClassName; michael@0: const bool mConstructable; michael@0: nsWeakPtr mWeakOwner; michael@0: }; michael@0: michael@0: //static michael@0: nsresult michael@0: nsDOMConstructor::Create(const char16_t* aName, michael@0: const nsDOMClassInfoData* aData, michael@0: const nsGlobalNameStruct* aNameStruct, michael@0: nsPIDOMWindow* aOwner, michael@0: nsDOMConstructor** aResult) michael@0: { michael@0: *aResult = nullptr; michael@0: // Prevent creating a constructor if aOwner is inner window which doesn't have michael@0: // an outer window. If the outer window doesn't have an inner window or the michael@0: // caller can't access the outer window's current inner window then try to use michael@0: // the owner (so long as it is, in fact, an inner window). If that doesn't michael@0: // work then prevent creation also. michael@0: nsPIDOMWindow* outerWindow = aOwner->GetOuterWindow(); michael@0: nsPIDOMWindow* currentInner = michael@0: outerWindow ? outerWindow->GetCurrentInnerWindow() : aOwner; michael@0: if (!currentInner || michael@0: (aOwner != currentInner && michael@0: !nsContentUtils::CanCallerAccess(currentInner) && michael@0: !(currentInner = aOwner)->IsInnerWindow())) { michael@0: return NS_ERROR_DOM_SECURITY_ERR; michael@0: } michael@0: michael@0: bool constructable = aNameStruct ? michael@0: IsConstructable(aNameStruct) : michael@0: IsConstructable(aData); michael@0: michael@0: *aResult = new nsDOMConstructor(aName, constructable, currentInner); michael@0: NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY); michael@0: NS_ADDREF(*aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMPL_ADDREF(nsDOMConstructor) michael@0: NS_IMPL_RELEASE(nsDOMConstructor) michael@0: NS_INTERFACE_MAP_BEGIN(nsDOMConstructor) michael@0: NS_INTERFACE_MAP_ENTRY(nsIDOMDOMConstructor) michael@0: NS_INTERFACE_MAP_ENTRY(nsISupports) michael@0: if (aIID.Equals(NS_GET_IID(nsIClassInfo))) { michael@0: #ifdef DEBUG michael@0: { michael@0: const nsGlobalNameStruct *name_struct = GetNameStruct(); michael@0: NS_ASSERTION(!name_struct || michael@0: mConstructable == IsConstructable(name_struct), michael@0: "Can't change constructability dynamically!"); michael@0: } michael@0: #endif michael@0: foundInterface = michael@0: NS_GetDOMClassInfoInstance(mConstructable ? michael@0: eDOMClassInfo_DOMConstructor_id : michael@0: eDOMClassInfo_DOMPrototype_id); michael@0: if (!foundInterface) { michael@0: *aInstancePtr = nullptr; michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: } else michael@0: NS_INTERFACE_MAP_END michael@0: michael@0: nsresult michael@0: nsDOMConstructor::PreCreate(JSContext *cx, JSObject *globalObj, JSObject **parentObj) michael@0: { michael@0: nsCOMPtr owner(do_QueryReferent(mWeakOwner)); michael@0: if (!owner) { michael@0: // Can't do anything. michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsGlobalWindow *win = static_cast(owner.get()); michael@0: return SetParentToWindow(win, parentObj); michael@0: } michael@0: michael@0: nsresult michael@0: nsDOMConstructor::Construct(nsIXPConnectWrappedNative *wrapper, JSContext * cx, michael@0: JS::Handle obj, const JS::CallArgs &args, michael@0: bool *_retval) michael@0: { michael@0: MOZ_ASSERT(obj); michael@0: michael@0: const nsGlobalNameStruct *name_struct = GetNameStruct(); michael@0: NS_ENSURE_TRUE(name_struct, NS_ERROR_FAILURE); michael@0: michael@0: if (!IsConstructable(name_struct)) { michael@0: // ignore return value, we return false anyway michael@0: return NS_ERROR_DOM_NOT_SUPPORTED_ERR; michael@0: } michael@0: michael@0: return BaseStubConstructor(mWeakOwner, name_struct, cx, obj, args); michael@0: } michael@0: michael@0: nsresult michael@0: nsDOMConstructor::HasInstance(nsIXPConnectWrappedNative *wrapper, michael@0: JSContext * cx, JS::Handle obj, michael@0: const jsval &v, bool *bp, bool *_retval) michael@0: michael@0: { michael@0: // No need to look these up in the hash. michael@0: *bp = false; michael@0: if (JSVAL_IS_PRIMITIVE(v)) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: JS::Rooted dom_obj(cx, v.toObjectOrNull()); michael@0: NS_ASSERTION(dom_obj, "nsDOMConstructor::HasInstance couldn't get object"); michael@0: michael@0: // This might not be the right object, if there are wrappers. Unwrap if we can. michael@0: JSObject *wrapped_obj = js::CheckedUnwrap(dom_obj, /* stopAtOuter = */ false); michael@0: if (wrapped_obj) michael@0: dom_obj = wrapped_obj; michael@0: michael@0: const JSClass *dom_class = JS_GetClass(dom_obj); michael@0: if (!dom_class) { michael@0: NS_ERROR("nsDOMConstructor::HasInstance can't get class."); michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: const nsGlobalNameStruct *name_struct; michael@0: nsresult rv = GetNameStruct(NS_ConvertASCIItoUTF16(dom_class->name), &name_struct); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: michael@0: if (!name_struct) { michael@0: // This isn't a normal DOM object, see if this constructor lives on its michael@0: // prototype chain. michael@0: JS::Rooted val(cx); michael@0: if (!JS_GetProperty(cx, obj, "prototype", &val)) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: if (JSVAL_IS_PRIMITIVE(val)) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: JS::Rooted dot_prototype(cx, val.toObjectOrNull()); michael@0: michael@0: JS::Rooted proto(cx, dom_obj); michael@0: for (;;) { michael@0: if (!JS_GetPrototype(cx, proto, &proto)) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: if (!proto) { michael@0: break; michael@0: } michael@0: if (proto == dot_prototype) { michael@0: *bp = true; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (name_struct->mType != nsGlobalNameStruct::eTypeClassConstructor && michael@0: name_struct->mType != nsGlobalNameStruct::eTypeExternalClassInfo && michael@0: name_struct->mType != nsGlobalNameStruct::eTypeExternalConstructorAlias) { michael@0: // Doesn't have DOM interfaces. michael@0: return NS_OK; michael@0: } michael@0: michael@0: const nsGlobalNameStruct *class_name_struct = GetNameStruct(); michael@0: NS_ENSURE_TRUE(class_name_struct, NS_ERROR_FAILURE); michael@0: michael@0: if (name_struct == class_name_struct) { michael@0: *bp = true; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager(); michael@0: NS_ASSERTION(nameSpaceManager, "Can't get namespace manager?"); michael@0: michael@0: const nsIID *class_iid; michael@0: if (class_name_struct->mType == nsGlobalNameStruct::eTypeInterface || michael@0: class_name_struct->mType == nsGlobalNameStruct::eTypeClassProto) { michael@0: class_iid = &class_name_struct->mIID; michael@0: } else if (class_name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) { michael@0: class_iid = michael@0: sClassInfoData[class_name_struct->mDOMClassInfoID].mProtoChainInterface; michael@0: } else if (class_name_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfo) { michael@0: class_iid = class_name_struct->mData->mProtoChainInterface; michael@0: } else if (class_name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias) { michael@0: const nsGlobalNameStruct* alias_struct = michael@0: nameSpaceManager->GetConstructorProto(class_name_struct); michael@0: if (!alias_struct) { michael@0: NS_ERROR("Couldn't get constructor prototype."); michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: if (alias_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) { michael@0: class_iid = michael@0: sClassInfoData[alias_struct->mDOMClassInfoID].mProtoChainInterface; michael@0: } else if (alias_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfo) { michael@0: class_iid = alias_struct->mData->mProtoChainInterface; michael@0: } else { michael@0: NS_ERROR("Expected eTypeClassConstructor or eTypeExternalClassInfo."); michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: } else { michael@0: *bp = false; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias) { michael@0: name_struct = nameSpaceManager->GetConstructorProto(name_struct); michael@0: if (!name_struct) { michael@0: NS_ERROR("Couldn't get constructor prototype."); michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: } michael@0: michael@0: NS_ASSERTION(name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor || michael@0: name_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfo, michael@0: "The constructor was set up with a struct of the wrong type."); michael@0: michael@0: const nsDOMClassInfoData *ci_data = nullptr; michael@0: if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor && michael@0: name_struct->mDOMClassInfoID >= 0) { michael@0: ci_data = &sClassInfoData[name_struct->mDOMClassInfoID]; michael@0: } else if (name_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfo) { michael@0: ci_data = name_struct->mData; michael@0: } michael@0: michael@0: nsCOMPtr michael@0: iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); michael@0: if (!iim) { michael@0: NS_ERROR("nsDOMConstructor::HasInstance can't get interface info mgr."); michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: nsCOMPtr if_info; michael@0: uint32_t count = 0; michael@0: const nsIID* class_interface; michael@0: while ((class_interface = ci_data->mInterfaces[count++])) { michael@0: if (class_iid->Equals(*class_interface)) { michael@0: *bp = true; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: iim->GetInfoForIID(class_interface, getter_AddRefs(if_info)); michael@0: if (!if_info) { michael@0: NS_ERROR("nsDOMConstructor::HasInstance can't get interface info."); michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: if_info->HasAncestor(class_iid, bp); michael@0: michael@0: if (*bp) { michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsDOMConstructor::ResolveInterfaceConstants(JSContext *cx, JS::Handle obj) michael@0: { michael@0: const nsGlobalNameStruct *class_name_struct = GetNameStruct(); michael@0: if (!class_name_struct) michael@0: return NS_ERROR_UNEXPECTED; michael@0: michael@0: const nsIID *class_iid; michael@0: if (class_name_struct->mType == nsGlobalNameStruct::eTypeInterface || michael@0: class_name_struct->mType == nsGlobalNameStruct::eTypeClassProto) { michael@0: class_iid = &class_name_struct->mIID; michael@0: } else if (class_name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) { michael@0: class_iid = michael@0: sClassInfoData[class_name_struct->mDOMClassInfoID].mProtoChainInterface; michael@0: } else if (class_name_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfo) { michael@0: class_iid = class_name_struct->mData->mProtoChainInterface; michael@0: } else { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult rv = DefineInterfaceConstants(cx, obj, class_iid); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMConstructor::ToString(nsAString &aResult) michael@0: { michael@0: aResult.AssignLiteral("[object "); michael@0: aResult.Append(mClassName); michael@0: aResult.Append(char16_t(']')); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: static nsresult michael@0: GetXPCProto(nsIXPConnect *aXPConnect, JSContext *cx, nsGlobalWindow *aWin, michael@0: const nsGlobalNameStruct *aNameStruct, michael@0: nsIXPConnectJSObjectHolder **aProto) michael@0: { michael@0: NS_ASSERTION(aNameStruct->mType == michael@0: nsGlobalNameStruct::eTypeClassConstructor || michael@0: aNameStruct->mType == nsGlobalNameStruct::eTypeExternalClassInfo, michael@0: "Wrong type!"); michael@0: michael@0: nsCOMPtr ci; michael@0: if (aNameStruct->mType == nsGlobalNameStruct::eTypeClassConstructor) { michael@0: int32_t id = aNameStruct->mDOMClassInfoID; michael@0: NS_ABORT_IF_FALSE(id >= 0, "Negative DOM classinfo?!?"); michael@0: michael@0: nsDOMClassInfoID ci_id = (nsDOMClassInfoID)id; michael@0: michael@0: ci = NS_GetDOMClassInfoInstance(ci_id); michael@0: michael@0: // In most cases we want to find the wrapped native prototype in michael@0: // aWin's scope and use that prototype for michael@0: // ClassName.prototype. But in the case where we're setting up michael@0: // "Window.prototype" or "ChromeWindow.prototype" we want to do michael@0: // the look up in aWin's outer window's scope since the inner michael@0: // window's wrapped native prototype comes from the outer michael@0: // window's scope. michael@0: if (ci_id == eDOMClassInfo_Window_id || michael@0: ci_id == eDOMClassInfo_ModalContentWindow_id || michael@0: ci_id == eDOMClassInfo_ChromeWindow_id) { michael@0: nsGlobalWindow *scopeWindow = aWin->GetOuterWindowInternal(); michael@0: michael@0: if (scopeWindow) { michael@0: aWin = scopeWindow; michael@0: } michael@0: } michael@0: } michael@0: else { michael@0: ci = nsDOMClassInfo::GetClassInfoInstance(aNameStruct->mData); michael@0: } michael@0: NS_ENSURE_TRUE(ci, NS_ERROR_UNEXPECTED); michael@0: michael@0: nsresult rv = michael@0: aXPConnect->GetWrappedNativePrototype(cx, aWin->GetGlobalJSObject(), ci, michael@0: aProto); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: JS::Rooted proto_obj(cx, (*aProto)->GetJSObject()); michael@0: if (!JS_WrapObject(cx, &proto_obj)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IF_RELEASE(*aProto); michael@0: return aXPConnect->HoldObject(cx, proto_obj, aProto); michael@0: } michael@0: michael@0: // Either ci_data must be non-null or name_struct must be non-null and of type michael@0: // eTypeClassProto. michael@0: static nsresult michael@0: ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx, michael@0: JS::Handle obj, const char16_t *name, michael@0: const nsDOMClassInfoData *ci_data, michael@0: const nsGlobalNameStruct *name_struct, michael@0: nsScriptNameSpaceManager *nameSpaceManager, michael@0: JSObject* aDot_prototype, michael@0: JS::MutableHandle ctorDesc) michael@0: { michael@0: JS::Rooted dot_prototype(cx, aDot_prototype); michael@0: NS_ASSERTION(ci_data || michael@0: (name_struct && michael@0: name_struct->mType == nsGlobalNameStruct::eTypeClassProto), michael@0: "Wrong type or missing ci_data!"); michael@0: michael@0: nsRefPtr constructor; michael@0: nsresult rv = nsDOMConstructor::Create(name, ci_data, name_struct, aWin, michael@0: getter_AddRefs(constructor)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: JS::Rooted v(cx); michael@0: michael@0: js::AssertSameCompartment(cx, obj); michael@0: rv = WrapNative(cx, constructor, &NS_GET_IID(nsIDOMDOMConstructor), michael@0: false, &v); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: FillPropertyDescriptor(ctorDesc, obj, 0, v); michael@0: // And make sure we wrap the value into the right compartment. Note that we michael@0: // do this with ctorDesc.value(), not with v, because we need v to be in the michael@0: // right compartment (that of the reflector of |constructor|) below. michael@0: if (!JS_WrapValue(cx, ctorDesc.value())) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: JS::Rooted class_obj(cx, &v.toObject()); michael@0: michael@0: const nsIID *primary_iid = &NS_GET_IID(nsISupports); michael@0: michael@0: if (!ci_data) { michael@0: primary_iid = &name_struct->mIID; michael@0: } michael@0: else if (ci_data->mProtoChainInterface) { michael@0: primary_iid = ci_data->mProtoChainInterface; michael@0: } michael@0: michael@0: nsCOMPtr if_info; michael@0: nsCOMPtr parent; michael@0: const char *class_parent_name = nullptr; michael@0: michael@0: if (!primary_iid->Equals(NS_GET_IID(nsISupports))) { michael@0: JSAutoCompartment ac(cx, class_obj); michael@0: michael@0: rv = DefineInterfaceConstants(cx, class_obj, primary_iid); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsCOMPtr michael@0: iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); michael@0: NS_ENSURE_TRUE(iim, NS_ERROR_NOT_AVAILABLE); michael@0: michael@0: iim->GetInfoForIID(primary_iid, getter_AddRefs(if_info)); michael@0: NS_ENSURE_TRUE(if_info, NS_ERROR_UNEXPECTED); michael@0: michael@0: const nsIID *iid = nullptr; michael@0: michael@0: if (ci_data && !ci_data->mHasClassInterface) { michael@0: if_info->GetIIDShared(&iid); michael@0: } else { michael@0: if_info->GetParent(getter_AddRefs(parent)); michael@0: NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED); michael@0: michael@0: parent->GetIIDShared(&iid); michael@0: } michael@0: michael@0: if (iid) { michael@0: if (!iid->Equals(NS_GET_IID(nsISupports))) { michael@0: if (ci_data && !ci_data->mHasClassInterface) { michael@0: // If the class doesn't have a class interface the primary michael@0: // interface is the interface that should be michael@0: // constructor.prototype.__proto__. michael@0: michael@0: if_info->GetNameShared(&class_parent_name); michael@0: } else { michael@0: // If the class does have a class interface (or there's no michael@0: // real class for this name) then the parent of the michael@0: // primary interface is what we want on michael@0: // constructor.prototype.__proto__. michael@0: michael@0: NS_ASSERTION(parent, "Whoa, this is bad, null parent here!"); michael@0: michael@0: parent->GetNameShared(&class_parent_name); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: { michael@0: JS::Rooted winobj(cx, aWin->FastGetGlobalJSObject()); michael@0: michael@0: JS::Rooted proto(cx); michael@0: michael@0: if (class_parent_name) { michael@0: JSAutoCompartment ac(cx, winobj); michael@0: michael@0: JS::Rooted val(cx); michael@0: if (!JS_LookupProperty(cx, winobj, CutPrefix(class_parent_name), &val)) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: if (val.isObject()) { michael@0: JS::Rooted obj(cx, &val.toObject()); michael@0: if (!JS_LookupProperty(cx, obj, "prototype", &val)) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: if (val.isObject()) { michael@0: proto = &val.toObject(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (dot_prototype) { michael@0: JSAutoCompartment ac(cx, dot_prototype); michael@0: JS::Rooted xpc_proto_proto(cx); michael@0: if (!::JS_GetPrototype(cx, dot_prototype, &xpc_proto_proto)) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: if (proto && michael@0: (!xpc_proto_proto || michael@0: JS_GetClass(xpc_proto_proto) == sObjectClass)) { michael@0: if (!JS_WrapObject(cx, &proto) || michael@0: !JS_SetPrototype(cx, dot_prototype, proto)) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: } michael@0: } else { michael@0: JSAutoCompartment ac(cx, winobj); michael@0: if (!proto) { michael@0: proto = JS_GetObjectPrototype(cx, winobj); michael@0: } michael@0: dot_prototype = ::JS_NewObjectWithUniqueType(cx, michael@0: &sDOMConstructorProtoClass, michael@0: proto, michael@0: winobj); michael@0: NS_ENSURE_TRUE(dot_prototype, NS_ERROR_OUT_OF_MEMORY); michael@0: } michael@0: } michael@0: michael@0: v = OBJECT_TO_JSVAL(dot_prototype); michael@0: michael@0: JSAutoCompartment ac(cx, class_obj); michael@0: michael@0: // Per ECMA, the prototype property is {DontEnum, DontDelete, ReadOnly} michael@0: if (!JS_WrapValue(cx, &v) || michael@0: !JS_DefineProperty(cx, class_obj, "prototype", v, michael@0: JSPROP_PERMANENT | JSPROP_READONLY, michael@0: JS_PropertyStub, JS_StrictPropertyStub)) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: static bool michael@0: OldBindingConstructorEnabled(const nsGlobalNameStruct *aStruct, michael@0: nsGlobalWindow *aWin, JSContext *cx) michael@0: { michael@0: MOZ_ASSERT(aStruct->mType == nsGlobalNameStruct::eTypeProperty || michael@0: aStruct->mType == nsGlobalNameStruct::eTypeClassConstructor || michael@0: aStruct->mType == nsGlobalNameStruct::eTypeExternalClassInfo); michael@0: michael@0: // Don't expose chrome only constructors to content windows. michael@0: if (aStruct->mChromeOnly) { michael@0: bool expose; michael@0: if (aStruct->mAllowXBL) { michael@0: expose = IsChromeOrXBL(cx, nullptr); michael@0: } else { michael@0: expose = nsContentUtils::IsSystemPrincipal(aWin->GetPrincipal()); michael@0: } michael@0: michael@0: if (!expose) { michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: // Don't expose CSSSupportsRule unless @supports processing is enabled. michael@0: if (aStruct->mDOMClassInfoID == eDOMClassInfo_CSSSupportsRule_id) { michael@0: if (!CSSSupportsRule::PrefEnabled()) { michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: // Don't expose CSSFontFeatureValuesRule unless the pref is enabled michael@0: if (aStruct->mDOMClassInfoID == eDOMClassInfo_CSSFontFeatureValuesRule_id) { michael@0: return nsCSSFontFeatureValuesRule::PrefEnabled(); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: nsWindowSH::NameStructEnabled(JSContext* aCx, nsGlobalWindow *aWin, michael@0: const nsAString& aName, michael@0: const nsGlobalNameStruct& aNameStruct) michael@0: { michael@0: const nsGlobalNameStruct* nameStruct = &aNameStruct; michael@0: if (nameStruct->mType == nsGlobalNameStruct::eTypeExternalClassInfoCreator) { michael@0: nsresult rv = GetExternalClassInfo(GetNameSpaceManager(), aName, nameStruct, michael@0: &nameStruct); michael@0: if (NS_FAILED(rv) || !nameStruct) { michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: return (nameStruct->mType != nsGlobalNameStruct::eTypeProperty && michael@0: nameStruct->mType != nsGlobalNameStruct::eTypeClassConstructor && michael@0: nameStruct->mType != nsGlobalNameStruct::eTypeExternalClassInfo) || michael@0: OldBindingConstructorEnabled(nameStruct, aWin, aCx); michael@0: } michael@0: michael@0: #ifdef RELEASE_BUILD michael@0: #define USE_CONTROLLERS_SHIM michael@0: #endif michael@0: michael@0: #ifdef USE_CONTROLLERS_SHIM michael@0: static const JSClass ControllersShimClass = { michael@0: "XULControllers", 0, michael@0: JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, michael@0: JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, nullptr michael@0: }; michael@0: #endif michael@0: michael@0: // static michael@0: nsresult michael@0: nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx, michael@0: JS::Handle obj, JS::Handle id, michael@0: JS::MutableHandle desc) michael@0: { michael@0: #ifdef USE_CONTROLLERS_SHIM michael@0: if (id == XPCJSRuntime::Get()->GetStringID(XPCJSRuntime::IDX_CONTROLLERS) && michael@0: !xpc::IsXrayWrapper(obj) && michael@0: !nsContentUtils::IsSystemPrincipal(aWin->GetPrincipal())) michael@0: { michael@0: if (aWin->GetDoc()) { michael@0: aWin->GetDoc()->WarnOnceAbout(nsIDocument::eWindow_Controllers); michael@0: } michael@0: JS::Rooted shim(cx, JS_NewObject(cx, &ControllersShimClass, JS::NullPtr(), obj)); michael@0: if (NS_WARN_IF(!shim)) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: FillPropertyDescriptor(desc, obj, JS::ObjectValue(*shim), /* readOnly = */ false); michael@0: return NS_OK; michael@0: } michael@0: #endif michael@0: michael@0: nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager(); michael@0: NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED); michael@0: michael@0: nsDependentJSString name(id); michael@0: michael@0: const char16_t *class_name = nullptr; michael@0: const nsGlobalNameStruct *name_struct = michael@0: nameSpaceManager->LookupName(name, &class_name); michael@0: michael@0: if (!name_struct) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: // The class_name had better match our name michael@0: MOZ_ASSERT(name.Equals(class_name)); michael@0: michael@0: NS_ENSURE_TRUE(class_name, NS_ERROR_UNEXPECTED); michael@0: michael@0: nsresult rv = NS_OK; michael@0: michael@0: if (name_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfoCreator) { michael@0: rv = GetExternalClassInfo(nameSpaceManager, name, name_struct, michael@0: &name_struct); michael@0: if (NS_FAILED(rv) || !name_struct) { michael@0: return rv; michael@0: } michael@0: } michael@0: michael@0: if (name_struct->mType == nsGlobalNameStruct::eTypeNewDOMBinding || michael@0: name_struct->mType == nsGlobalNameStruct::eTypeInterface || michael@0: name_struct->mType == nsGlobalNameStruct::eTypeClassProto || michael@0: name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) { michael@0: // Lookup new DOM bindings. michael@0: DefineInterface getOrCreateInterfaceObject = michael@0: name_struct->mDefineDOMInterface; michael@0: if (getOrCreateInterfaceObject) { michael@0: if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor && michael@0: !OldBindingConstructorEnabled(name_struct, aWin, cx)) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: ConstructorEnabled* checkEnabledForScope = name_struct->mConstructorEnabled; michael@0: // We do the enabled check on the current compartment of cx, but for the michael@0: // actual object we pass in the underlying object in the Xray case. That michael@0: // way the callee can decide whether to allow access based on the caller michael@0: // or the window being touched. michael@0: JS::Rooted global(cx, michael@0: js::CheckedUnwrap(obj, /* stopAtOuter = */ false)); michael@0: if (!global) { michael@0: return NS_ERROR_DOM_SECURITY_ERR; michael@0: } michael@0: if (checkEnabledForScope && !checkEnabledForScope(cx, global)) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: // The DOM constructor resolve machinery interacts with Xrays in tricky michael@0: // ways, and there are some asymmetries that are important to understand. michael@0: // michael@0: // In the regular (non-Xray) case, we only want to resolve constructors michael@0: // once (so that if they're deleted, they don't reappear). We do this by michael@0: // stashing the constructor in a slot on the global, such that we can see michael@0: // during resolve whether we've created it already. This is rather michael@0: // memory-intensive, so we don't try to maintain these semantics when michael@0: // manipulating a global over Xray (so the properties just re-resolve if michael@0: // they've been deleted). michael@0: // michael@0: // Unfortunately, there's a bit of an impedance-mismatch between the Xray michael@0: // and non-Xray machinery. The Xray machinery wants an API that returns a michael@0: // JSPropertyDescriptor, so that the resolve hook doesn't have to get michael@0: // snared up with trying to define a property on the Xray holder. At the michael@0: // same time, the DefineInterface callbacks are set up to define things michael@0: // directly on the global. And re-jiggering them to return property michael@0: // descriptors is tricky, because some DefineInterface callbacks define michael@0: // multiple things (like the Image() alias for HTMLImageElement). michael@0: // michael@0: // So the setup is as-follows: michael@0: // michael@0: // * The resolve function takes a JSPropertyDescriptor, but in the michael@0: // non-Xray case, callees may define things directly on the global, and michael@0: // set the value on the property descriptor to |undefined| to indicate michael@0: // that there's nothing more for the caller to do. We assert against michael@0: // this behavior in the Xray case. michael@0: // michael@0: // * We make sure that we do a non-Xray resolve first, so that all the michael@0: // slots are set up. In the Xray case, this means unwrapping and doing michael@0: // a non-Xray resolve before doing the Xray resolve. michael@0: // michael@0: // This all could use some grand refactoring, but for now we just limp michael@0: // along. michael@0: if (xpc::WrapperFactory::IsXrayWrapper(obj)) { michael@0: JS::Rooted interfaceObject(cx); michael@0: { michael@0: JSAutoCompartment ac(cx, global); michael@0: interfaceObject = getOrCreateInterfaceObject(cx, global, id, false); michael@0: } michael@0: if (NS_WARN_IF(!interfaceObject)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: if (!JS_WrapObject(cx, &interfaceObject)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: FillPropertyDescriptor(desc, obj, 0, JS::ObjectValue(*interfaceObject)); michael@0: } else { michael@0: JS::Rooted interfaceObject(cx, michael@0: getOrCreateInterfaceObject(cx, obj, id, true)); michael@0: if (NS_WARN_IF(!interfaceObject)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: // We've already defined the property. We indicate this to the caller michael@0: // by filling a property descriptor with JS::UndefinedValue() as the michael@0: // value. We still have to fill in a property descriptor, though, so michael@0: // that the caller knows the property is in fact on this object. It michael@0: // doesn't matter what we pass for the "readonly" argument here. michael@0: FillPropertyDescriptor(desc, obj, JS::UndefinedValue(), false); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: if (name_struct->mType == nsGlobalNameStruct::eTypeInterface) { michael@0: // We're resolving a name of a DOM interface for which there is no michael@0: // direct DOM class, create a constructor object... michael@0: nsRefPtr constructor; michael@0: rv = nsDOMConstructor::Create(class_name, michael@0: nullptr, michael@0: name_struct, michael@0: static_cast(aWin), michael@0: getter_AddRefs(constructor)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: JS::Rooted v(cx); michael@0: js::AssertSameCompartment(cx, obj); michael@0: rv = WrapNative(cx, constructor, &NS_GET_IID(nsIDOMDOMConstructor), michael@0: false, &v); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: JS::Rooted class_obj(cx, &v.toObject()); michael@0: michael@0: // ... and define the constants from the DOM interface on that michael@0: // constructor object. michael@0: michael@0: { michael@0: JSAutoCompartment ac(cx, class_obj); michael@0: rv = DefineInterfaceConstants(cx, class_obj, &name_struct->mIID); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } michael@0: michael@0: if (!JS_WrapValue(cx, &v)) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: FillPropertyDescriptor(desc, obj, 0, v); michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor || michael@0: name_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfo) { michael@0: if (!OldBindingConstructorEnabled(name_struct, aWin, cx)) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Create the XPConnect prototype for our classinfo, PostCreateProto will michael@0: // set up the prototype chain. This will go ahead and define things on the michael@0: // actual window's global. michael@0: nsCOMPtr proto_holder; michael@0: rv = GetXPCProto(sXPConnect, cx, aWin, name_struct, michael@0: getter_AddRefs(proto_holder)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: bool isXray = xpc::WrapperFactory::IsXrayWrapper(obj); michael@0: MOZ_ASSERT_IF(obj != aWin->GetGlobalJSObject(), isXray); michael@0: if (!isXray) { michael@0: // GetXPCProto already defined the property for us michael@0: FillPropertyDescriptor(desc, obj, JS::UndefinedValue(), false); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // This is the Xray case. Look up the constructor object for this michael@0: // prototype. michael@0: JS::Rooted dot_prototype(cx, proto_holder->GetJSObject()); michael@0: NS_ENSURE_STATE(dot_prototype); michael@0: michael@0: const nsDOMClassInfoData *ci_data; michael@0: if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) { michael@0: ci_data = &sClassInfoData[name_struct->mDOMClassInfoID]; michael@0: } else { michael@0: ci_data = name_struct->mData; michael@0: } michael@0: michael@0: return ResolvePrototype(sXPConnect, aWin, cx, obj, class_name, ci_data, michael@0: name_struct, nameSpaceManager, dot_prototype, michael@0: desc); michael@0: } michael@0: michael@0: if (name_struct->mType == nsGlobalNameStruct::eTypeClassProto) { michael@0: // We don't have a XPConnect prototype object, let ResolvePrototype create michael@0: // one. michael@0: return ResolvePrototype(sXPConnect, aWin, cx, obj, class_name, nullptr, michael@0: name_struct, nameSpaceManager, nullptr, desc); michael@0: } michael@0: michael@0: if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias) { michael@0: const nsGlobalNameStruct *alias_struct = michael@0: nameSpaceManager->GetConstructorProto(name_struct); michael@0: NS_ENSURE_TRUE(alias_struct, NS_ERROR_UNEXPECTED); michael@0: michael@0: // We need to use the XPConnect prototype for the DOM class that this michael@0: // constructor is an alias for (for example for Image we need the prototype michael@0: // for HTMLImageElement). michael@0: nsCOMPtr proto_holder; michael@0: rv = GetXPCProto(sXPConnect, cx, aWin, alias_struct, michael@0: getter_AddRefs(proto_holder)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: JSObject* dot_prototype = proto_holder->GetJSObject(); michael@0: NS_ENSURE_STATE(dot_prototype); michael@0: michael@0: const nsDOMClassInfoData *ci_data; michael@0: if (alias_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) { michael@0: ci_data = &sClassInfoData[alias_struct->mDOMClassInfoID]; michael@0: } else if (alias_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfo) { michael@0: ci_data = alias_struct->mData; michael@0: } else { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: return ResolvePrototype(sXPConnect, aWin, cx, obj, class_name, ci_data, michael@0: name_struct, nameSpaceManager, nullptr, desc); michael@0: } michael@0: michael@0: if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructor) { michael@0: nsRefPtr constructor; michael@0: rv = nsDOMConstructor::Create(class_name, nullptr, name_struct, michael@0: static_cast(aWin), michael@0: getter_AddRefs(constructor)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: JS::Rooted val(cx); michael@0: js::AssertSameCompartment(cx, obj); michael@0: rv = WrapNative(cx, constructor, &NS_GET_IID(nsIDOMDOMConstructor), michael@0: true, &val); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: NS_ASSERTION(val.isObject(), "Why didn't we get a JSObject?"); michael@0: michael@0: FillPropertyDescriptor(desc, obj, 0, val); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (name_struct->mType == nsGlobalNameStruct::eTypeProperty) { michael@0: if (!OldBindingConstructorEnabled(name_struct, aWin, cx)) michael@0: return NS_OK; michael@0: michael@0: // Before defining a global property, check for a named subframe of the michael@0: // same name. If it exists, we don't want to shadow it. michael@0: nsCOMPtr childWin = aWin->GetChildWindow(name); michael@0: if (childWin) michael@0: return NS_OK; michael@0: michael@0: nsCOMPtr native(do_CreateInstance(name_struct->mCID, &rv)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: JS::Rooted prop_val(cx, JS::UndefinedValue()); // Property value. michael@0: michael@0: nsCOMPtr gpi(do_QueryInterface(native)); michael@0: if (gpi) { michael@0: rv = gpi->Init(aWin, &prop_val); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } michael@0: michael@0: if (JSVAL_IS_PRIMITIVE(prop_val) && !JSVAL_IS_NULL(prop_val)) { michael@0: if (aWin->IsOuterWindow()) { michael@0: nsGlobalWindow *inner = aWin->GetCurrentInnerWindowInternal(); michael@0: NS_ENSURE_TRUE(inner, NS_ERROR_UNEXPECTED); michael@0: } michael@0: michael@0: rv = WrapNative(cx, native, true, &prop_val); michael@0: } michael@0: michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: if (!JS_WrapValue(cx, &prop_val)) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: FillPropertyDescriptor(desc, obj, prop_val, false); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: template michael@0: static nsresult michael@0: LocationSetterGuts(JSContext *cx, JSObject *obj, JS::MutableHandle vp) michael@0: { michael@0: // This function duplicates some of the logic in XPC_WN_HelperSetProperty michael@0: obj = js::CheckedUnwrap(obj, /* stopAtOuter = */ false); michael@0: if (!IS_WN_REFLECTOR(obj)) michael@0: return NS_ERROR_XPC_BAD_CONVERT_JS; michael@0: XPCWrappedNative *wrapper = XPCWrappedNative::Get(obj); michael@0: michael@0: // The error checks duplicate code in THROW_AND_RETURN_IF_BAD_WRAPPER michael@0: NS_ENSURE_TRUE(!wrapper || wrapper->IsValid(), NS_ERROR_XPC_HAS_BEEN_SHUTDOWN); michael@0: michael@0: nsCOMPtr xpcomObj = do_QueryWrappedNative(wrapper, obj); michael@0: NS_ENSURE_TRUE(xpcomObj, NS_ERROR_UNEXPECTED); michael@0: michael@0: nsCOMPtr location; michael@0: nsresult rv = xpcomObj->GetLocation(getter_AddRefs(location)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Grab the value we're being set to before we stomp on |vp| michael@0: JS::Rooted val(cx, JS::ToString(cx, vp)); michael@0: NS_ENSURE_TRUE(val, NS_ERROR_UNEXPECTED); michael@0: michael@0: // Make sure |val| stays alive below michael@0: JS::Anchor anchor(val); michael@0: michael@0: // We have to wrap location into vp before null-checking location, to michael@0: // avoid assigning the wrong thing into the slot. michael@0: rv = WrapNative(cx, location, &NS_GET_IID(nsIDOMLocation), true, vp); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: if (!location) { michael@0: // Make this a no-op michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsDependentJSString depStr; michael@0: NS_ENSURE_TRUE(depStr.init(cx, val), NS_ERROR_UNEXPECTED); michael@0: michael@0: return location->SetHref(depStr); michael@0: } michael@0: michael@0: template michael@0: static bool michael@0: LocationSetter(JSContext *cx, JS::Handle obj, JS::Handle id, bool strict, michael@0: JS::MutableHandle vp) michael@0: { michael@0: nsresult rv = LocationSetterGuts(cx, obj, vp); michael@0: if (NS_FAILED(rv)) { michael@0: xpc::Throw(cx, rv); michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: static bool michael@0: LocationSetterUnwrapper(JSContext *cx, JS::Handle obj_, JS::Handle id, michael@0: bool strict, JS::MutableHandle vp) michael@0: { michael@0: JS::Rooted obj(cx, obj_); michael@0: michael@0: JSObject *wrapped = XPCWrapper::UnsafeUnwrapSecurityWrapper(obj); michael@0: if (wrapped) { michael@0: obj = wrapped; michael@0: } michael@0: michael@0: return LocationSetter(cx, obj, id, strict, vp); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj_, jsid id_, JSObject **objp, michael@0: bool *_retval) michael@0: { michael@0: JS::Rooted obj(cx, obj_); michael@0: JS::Rooted id(cx, id_); michael@0: michael@0: if (!JSID_IS_STRING(id)) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: MOZ_ASSERT(*_retval == true); // guaranteed by XPC_WN_Helper_NewResolve michael@0: michael@0: nsGlobalWindow *win = nsGlobalWindow::FromWrapper(wrapper); michael@0: MOZ_ASSERT(win->IsInnerWindow()); michael@0: michael@0: // Don't resolve standard classes on XrayWrappers, only resolve them if we're michael@0: // resolving on the real global object. michael@0: bool isXray = xpc::WrapperFactory::IsXrayWrapper(obj); michael@0: if (!isXray) { michael@0: bool did_resolve = false; michael@0: if (!JS_ResolveStandardClass(cx, obj, id, &did_resolve)) { michael@0: // Return NS_OK to avoid stomping over the exception that was passed michael@0: // down from the ResolveStandardClass call. michael@0: *_retval = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (did_resolve) { michael@0: *objp = obj; michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: // WebIDL quickstubs handle location for us, but Xrays don't see those. So if michael@0: // we're an Xray, we have to resolve stuff here to make "window.location = michael@0: // someString" work. michael@0: if (sLocation_id == id && isXray) { michael@0: nsCOMPtr location; michael@0: nsresult rv = win->GetLocation(getter_AddRefs(location)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: JS::Rooted v(cx); michael@0: rv = WrapNative(cx, location, &NS_GET_IID(nsIDOMLocation), true, &v); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: bool ok = JS_DefinePropertyById(cx, obj, id, v, JS_PropertyStub, michael@0: LocationSetterUnwrapper, michael@0: JSPROP_PERMANENT | JSPROP_ENUMERATE); michael@0: michael@0: if (!ok) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: *objp = obj; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // WebIDL quickstubs handle "top" for us, but Xrays don't see those. So if michael@0: // we're an Xray and we want "top" to be JSPROP_PERMANENT, we need to resolve michael@0: // it here. michael@0: if (sTop_id == id && isXray) { michael@0: nsCOMPtr top; michael@0: nsresult rv = win->GetScriptableTop(getter_AddRefs(top)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: JS::Rooted v(cx); michael@0: js::AssertSameCompartment(cx, obj); michael@0: rv = WrapNative(cx, top, &NS_GET_IID(nsIDOMWindow), true, &v); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Hold on to the top window object as a global property so we michael@0: // don't need to worry about losing expando properties etc. michael@0: if (!JS_DefinePropertyById(cx, obj, id, v, JS_PropertyStub, JS_StrictPropertyStub, michael@0: JSPROP_READONLY | JSPROP_PERMANENT | michael@0: JSPROP_ENUMERATE)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: *objp = obj; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (isXray) { michael@0: // We promise to resolve on the underlying object first. That will create michael@0: // the actual interface object if needed and store it in a data structure michael@0: // hanging off the global. Then our second call will wrap up in an Xray as michael@0: // needed. We do things this way because we use the existence of the michael@0: // object in that data structure as a flag that indicates that its name michael@0: // (and any relevant named constructor names) has been resolved before; michael@0: // this allows us to avoid re-resolving in the Xray case if the property is michael@0: // deleted by page script. michael@0: JS::Rooted global(cx, michael@0: js::UncheckedUnwrap(obj, /* stopAtOuter = */ false)); michael@0: JSAutoCompartment ac(cx, global); michael@0: JS::Rooted desc(cx); michael@0: if (!win->DoNewResolve(cx, global, id, &desc)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: // If we have an object here, that means we resolved the property. michael@0: // But if the value is undefined, that means that GlobalResolve michael@0: // also already defined it, so we don't have to. michael@0: if (desc.object() && !desc.value().isUndefined() && michael@0: !JS_DefinePropertyById(cx, global, id, desc.value(), michael@0: desc.getter(), desc.setter(), michael@0: desc.attributes())) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: } michael@0: michael@0: JS::Rooted desc(cx); michael@0: if (!win->DoNewResolve(cx, obj, id, &desc)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: if (desc.object()) { michael@0: // If we have an object here, that means we resolved the property. michael@0: // But if the value is undefined, that means that GlobalResolve michael@0: // also already defined it, so we don't have to. Note that in the michael@0: // Xray case we should never see undefined. michael@0: MOZ_ASSERT_IF(isXray, !desc.value().isUndefined()); michael@0: if (!desc.value().isUndefined() && michael@0: !JS_DefinePropertyById(cx, obj, id, desc.value(), michael@0: desc.getter(), desc.setter(), michael@0: desc.attributes())) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: *objp = obj; michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (sDocument_id == id) { michael@0: nsCOMPtr document = win->GetDoc(); michael@0: JS::Rooted v(cx); michael@0: nsresult rv = WrapNative(cx, document, document, michael@0: &NS_GET_IID(nsIDOMDocument), &v, false); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // nsIDocument::WrapObject will handle defining the property. michael@0: *objp = obj; michael@0: michael@0: // NB: We need to do this for any Xray wrapper. michael@0: if (xpc::WrapperFactory::IsXrayWrapper(obj)) { michael@0: *_retval = JS_WrapValue(cx, &v) && michael@0: JS_DefineProperty(cx, obj, "document", v, michael@0: JSPROP_READONLY | JSPROP_ENUMERATE, michael@0: JS_PropertyStub, JS_StrictPropertyStub); michael@0: if (!*_retval) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: return nsDOMGenericSH::NewResolve(wrapper, cx, obj, id, objp, _retval); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindowSH::OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx, michael@0: JSObject * obj, JSObject * *_retval) michael@0: { michael@0: nsGlobalWindow *origWin = nsGlobalWindow::FromWrapper(wrapper); michael@0: nsGlobalWindow *win = origWin->GetOuterWindowInternal(); michael@0: michael@0: if (!win) { michael@0: // If we no longer have an outer window. No code should ever be michael@0: // running on a window w/o an outer, which means this hook should michael@0: // never be called when we have no outer. But just in case, return michael@0: // null to prevent leaking an inner window to code in a different michael@0: // window. michael@0: *_retval = nullptr; michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: JS::Rooted winObj(cx, win->FastGetGlobalJSObject()); michael@0: MOZ_ASSERT(winObj); michael@0: michael@0: // Note that while |wrapper| is same-compartment with cx, the outer window michael@0: // might not be. If we're running script in an inactive scope and evalute michael@0: // |this|, the outer window is actually a cross-compartment wrapper. So we michael@0: // need to wrap here. michael@0: if (!JS_WrapObject(cx, &winObj)) { michael@0: *_retval = nullptr; michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: *_retval = winObj; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsLocationSH::PreCreate(nsISupports *nativeObj, JSContext *cx, michael@0: JSObject *globalObj, JSObject **parentObj) michael@0: { michael@0: // window.location can be held onto by both evil pages that want to track the michael@0: // user's progress on the web and bookmarklets that want to use the location michael@0: // object. Parent it to the outer window so that access checks do the Right michael@0: // Thing. michael@0: *parentObj = globalObj; michael@0: michael@0: nsCOMPtr safeLoc(do_QueryInterface(nativeObj)); michael@0: if (!safeLoc) { michael@0: // Oops, this wasn't really a location object. This can happen if someone michael@0: // tries to use our scriptable helper as a real object and tries to wrap michael@0: // it, see bug 319296 michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsLocation *loc = (nsLocation *)safeLoc.get(); michael@0: nsIDocShell *ds = loc->GetDocShell(); michael@0: if (!ds) { michael@0: NS_WARNING("Refusing to create a location in the wrong scope"); michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: nsCOMPtr sgo = do_GetInterface(ds); michael@0: if (!sgo) { michael@0: NS_WARNING("Refusing to create a location in the wrong scope because the " michael@0: "docshell is being destroyed"); michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: *parentObj = sgo->GetGlobalJSObject(); michael@0: return *parentObj ? NS_OK : NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsLocationSH::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, jsid aId, jsval *vp, bool *_retval) michael@0: { michael@0: JS::Rooted rootedObj(cx, obj); michael@0: michael@0: // Shadowing protection. This will go away when nsLocation moves to the new michael@0: // bindings. michael@0: JS::Rooted id(cx, aId); michael@0: if (wrapper->HasNativeMember(id)) { michael@0: JS_ReportError(cx, "Permission denied to shadow native property"); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsLocation* location = static_cast(GetNative(wrapper, rootedObj)); michael@0: location->PreserveWrapper(location); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // EventTarget helper michael@0: michael@0: NS_IMETHODIMP michael@0: nsEventTargetSH::PreCreate(nsISupports *nativeObj, JSContext *cx, michael@0: JSObject *aGlobalObj, JSObject **parentObj) michael@0: { michael@0: JS::Rooted globalObj(cx, aGlobalObj); michael@0: DOMEventTargetHelper* target = DOMEventTargetHelper::FromSupports(nativeObj); michael@0: michael@0: nsCOMPtr native_parent; michael@0: target->GetParentObject(getter_AddRefs(native_parent)); michael@0: michael@0: *parentObj = native_parent ? native_parent->GetGlobalJSObject() : globalObj; michael@0: michael@0: return *parentObj ? NS_OK : NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsEventTargetSH::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, jsid id, jsval *vp, bool *_retval) michael@0: { michael@0: nsEventTargetSH::PreserveWrapper(GetNative(wrapper, obj)); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: nsEventTargetSH::PreserveWrapper(nsISupports *aNative) michael@0: { michael@0: DOMEventTargetHelper* target = DOMEventTargetHelper::FromSupports(aNative); michael@0: target->PreserveWrapper(aNative); michael@0: } michael@0: michael@0: // Generic array scriptable helper. michael@0: michael@0: NS_IMETHODIMP michael@0: nsGenericArraySH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *aObj, jsid aId, JSObject **objp, michael@0: bool *_retval) michael@0: { michael@0: JS::Rooted obj(cx, aObj); michael@0: JS::Rooted id(cx, aId); michael@0: if (id == sLength_id) { michael@0: // Bail early; this isn't something we're interested in michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool is_number = false; michael@0: int32_t n = GetArrayIndexFromId(cx, id, &is_number); michael@0: michael@0: if (is_number && n >= 0) { michael@0: // XXX The following is a cheap optimization to avoid hitting xpconnect to michael@0: // get the length. We may want to consider asking our concrete michael@0: // implementation for the length, and falling back onto the GetProperty if michael@0: // it doesn't provide one. michael@0: michael@0: uint32_t length; michael@0: nsresult rv = GetLength(wrapper, cx, obj, &length); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: uint32_t index = uint32_t(n); michael@0: if (index < length) { michael@0: *_retval = ::JS_DefineElement(cx, obj, index, JSVAL_VOID, nullptr, nullptr, michael@0: JSPROP_ENUMERATE | JSPROP_SHARED); michael@0: *objp = obj; michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsGenericArraySH::GetLength(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JS::Handle obj, uint32_t *length) michael@0: { michael@0: *length = 0; michael@0: michael@0: JS::Rooted lenval(cx); michael@0: if (!JS_GetProperty(cx, obj, "length", &lenval)) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: if (!JSVAL_IS_INT(lenval)) { michael@0: // This can apparently happen with some sparse array impls falling back michael@0: // onto this code. michael@0: return NS_OK; michael@0: } michael@0: michael@0: int32_t slen = JSVAL_TO_INT(lenval); michael@0: if (slen < 0) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: *length = (uint32_t)slen; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsGenericArraySH::Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *aObj, bool *_retval) michael@0: { michael@0: // Recursion protection in case someone tries to be smart and call michael@0: // the enumerate hook from a user defined .length getter, or michael@0: // somesuch. michael@0: michael@0: JS::Rooted obj(cx, aObj); michael@0: static bool sCurrentlyEnumerating; michael@0: michael@0: if (sCurrentlyEnumerating) { michael@0: // Don't recurse to death. michael@0: return NS_OK; michael@0: } michael@0: michael@0: sCurrentlyEnumerating = true; michael@0: michael@0: JS::Rooted len_val(cx); michael@0: bool ok = ::JS_GetProperty(cx, obj, "length", &len_val); michael@0: michael@0: if (ok && JSVAL_IS_INT(len_val)) { michael@0: int32_t length = JSVAL_TO_INT(len_val); michael@0: michael@0: for (int32_t i = 0; ok && i < length; ++i) { michael@0: ok = ::JS_DefineElement(cx, obj, i, JSVAL_VOID, nullptr, nullptr, michael@0: JSPROP_ENUMERATE | JSPROP_SHARED); michael@0: } michael@0: } michael@0: michael@0: sCurrentlyEnumerating = false; michael@0: michael@0: return ok ? NS_OK : NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: // Array scriptable helper michael@0: michael@0: NS_IMETHODIMP michael@0: nsArraySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *aObj, jsid aId, jsval *vp, bool *_retval) michael@0: { michael@0: JS::Rooted obj(cx, aObj); michael@0: JS::Rooted id(cx, aId); michael@0: bool is_number = false; michael@0: int32_t n = GetArrayIndexFromId(cx, id, &is_number); michael@0: michael@0: nsresult rv = NS_OK; michael@0: michael@0: if (is_number) { michael@0: if (n < 0) { michael@0: return NS_ERROR_DOM_INDEX_SIZE_ERR; michael@0: } michael@0: michael@0: // Make sure rv == NS_OK here, so GetItemAt implementations that never fail michael@0: // don't have to set rv. michael@0: rv = NS_OK; michael@0: nsWrapperCache *cache = nullptr; michael@0: nsISupports* array_item = michael@0: GetItemAt(GetNative(wrapper, obj), n, &cache, &rv); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: if (array_item) { michael@0: JS::Rooted rval(cx); michael@0: rv = WrapNative(cx, array_item, cache, true, &rval); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: *vp = rval; michael@0: michael@0: rv = NS_SUCCESS_I_DID_SOMETHING; michael@0: } michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: michael@0: // CSSRuleList scriptable helper michael@0: michael@0: nsISupports* michael@0: nsCSSRuleListSH::GetItemAt(nsISupports *aNative, uint32_t aIndex, michael@0: nsWrapperCache **aCache, nsresult *aResult) michael@0: { michael@0: nsICSSRuleList* list = static_cast(aNative); michael@0: #ifdef DEBUG michael@0: { michael@0: nsCOMPtr list_qi = do_QueryInterface(aNative); michael@0: michael@0: // If this assertion fires the QI implementation for the object in michael@0: // question doesn't use the nsICSSRuleList pointer as the nsISupports michael@0: // pointer. That must be fixed, or we'll crash... michael@0: NS_ABORT_IF_FALSE(list_qi == list, "Uh, fix QI!"); michael@0: } michael@0: #endif michael@0: michael@0: return list->Item(aIndex); michael@0: } michael@0: michael@0: michael@0: // Storage2SH michael@0: michael@0: // One reason we need a newResolve hook is that in order for michael@0: // enumeration of storage object keys to work the keys we're michael@0: // enumerating need to exist on the storage object for the JS engine michael@0: // to find them. michael@0: michael@0: NS_IMETHODIMP michael@0: nsStorage2SH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, jsid aId, JSObject **objp, michael@0: bool *_retval) michael@0: { michael@0: JS::Rooted id(cx, aId); michael@0: if (ObjectIsNativeWrapper(cx, obj)) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: JS::Rooted realObj(cx, wrapper->GetJSObject()); michael@0: michael@0: JSAutoCompartment ac(cx, realObj); michael@0: michael@0: // First check to see if the property is defined on our prototype, michael@0: // after converting id to a string if it's an integer. michael@0: michael@0: JS::Rooted jsstr(cx, IdToString(cx, id)); michael@0: if (!jsstr) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: JS::Rooted proto(cx); michael@0: if (!::JS_GetPrototype(cx, realObj, &proto)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: bool hasProp; michael@0: michael@0: if (proto && michael@0: (::JS_HasPropertyById(cx, proto, id, &hasProp) && michael@0: hasProp)) { michael@0: // We found the property we're resolving on the prototype, michael@0: // nothing left to do here then. michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // We're resolving property that doesn't exist on the prototype, michael@0: // check if the key exists in the storage object. michael@0: michael@0: nsCOMPtr storage(do_QueryWrappedNative(wrapper)); michael@0: michael@0: nsDependentJSString depStr; michael@0: NS_ENSURE_TRUE(depStr.init(cx, jsstr), NS_ERROR_UNEXPECTED); michael@0: michael@0: // GetItem() will return null if the caller can't access the session michael@0: // storage item. michael@0: nsAutoString data; michael@0: nsresult rv = storage->GetItem(depStr, data); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: if (!DOMStringIsNull(data)) { michael@0: if (!::JS_DefinePropertyById(cx, realObj, id, JSVAL_VOID, nullptr, michael@0: nullptr, JSPROP_ENUMERATE)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: *objp = realObj; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsStorage2SH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *aObj, jsid aId, jsval *vp, bool *_retval) michael@0: { michael@0: JS::Rooted obj(cx, aObj); michael@0: JS::Rooted id(cx, aId); michael@0: nsCOMPtr storage(do_QueryWrappedNative(wrapper)); michael@0: NS_ENSURE_TRUE(storage, NS_ERROR_UNEXPECTED); michael@0: michael@0: JSString* key = IdToString(cx, id); michael@0: NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED); michael@0: michael@0: nsDependentJSString keyStr; michael@0: NS_ENSURE_TRUE(keyStr.init(cx, key), NS_ERROR_UNEXPECTED); michael@0: michael@0: // For native wrappers, do not get random names on storage objects. michael@0: if (ObjectIsNativeWrapper(cx, obj)) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: nsAutoString val; michael@0: nsresult rv = storage->GetItem(keyStr, val); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: if (DOMStringIsNull(val)) { michael@0: // No such key. michael@0: *vp = JSVAL_VOID; michael@0: } else { michael@0: JSString* str = michael@0: JS_NewUCStringCopyN(cx, static_cast(val.get()), michael@0: val.Length()); michael@0: NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: *vp = STRING_TO_JSVAL(str); michael@0: } michael@0: michael@0: return NS_SUCCESS_I_DID_SOMETHING; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsStorage2SH::SetProperty(nsIXPConnectWrappedNative *wrapper, michael@0: JSContext *cx, JSObject *obj, jsid aId, michael@0: jsval *vp, bool *_retval) michael@0: { michael@0: JS::Rooted id(cx, aId); michael@0: nsCOMPtr storage(do_QueryWrappedNative(wrapper)); michael@0: NS_ENSURE_TRUE(storage, NS_ERROR_UNEXPECTED); michael@0: michael@0: JSString *key = IdToString(cx, id); michael@0: NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED); michael@0: michael@0: nsDependentJSString keyStr; michael@0: NS_ENSURE_TRUE(keyStr.init(cx, key), NS_ERROR_UNEXPECTED); michael@0: michael@0: JS::Rooted val(cx, *vp); michael@0: JSString *value = JS::ToString(cx, val); michael@0: NS_ENSURE_TRUE(value, NS_ERROR_UNEXPECTED); michael@0: michael@0: nsDependentJSString valueStr; michael@0: NS_ENSURE_TRUE(valueStr.init(cx, value), NS_ERROR_UNEXPECTED); michael@0: michael@0: nsresult rv = storage->SetItem(keyStr, valueStr); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: rv = NS_SUCCESS_I_DID_SOMETHING; michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsStorage2SH::DelProperty(nsIXPConnectWrappedNative *wrapper, michael@0: JSContext *cx, JSObject *obj, jsid aId, michael@0: bool *_retval) michael@0: { michael@0: JS::Rooted id(cx, aId); michael@0: nsCOMPtr storage(do_QueryWrappedNative(wrapper)); michael@0: NS_ENSURE_TRUE(storage, NS_ERROR_UNEXPECTED); michael@0: michael@0: JSString *key = IdToString(cx, id); michael@0: NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED); michael@0: michael@0: nsDependentJSString keyStr; michael@0: NS_ENSURE_TRUE(keyStr.init(cx, key), NS_ERROR_UNEXPECTED); michael@0: michael@0: nsresult rv = storage->RemoveItem(keyStr); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: michael@0: *_retval = true; michael@0: return NS_SUCCESS_I_DID_SOMETHING; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsStorage2SH::NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *obj, uint32_t enum_op, jsval *statep, michael@0: jsid *idp, bool *_retval) michael@0: { michael@0: if (enum_op == JSENUMERATE_INIT || enum_op == JSENUMERATE_INIT_ALL) { michael@0: nsCOMPtr storage(do_QueryWrappedNative(wrapper)); michael@0: michael@0: // XXXndeakin need to free the keys afterwards michael@0: nsTArray *keys = storage->GetKeys(); michael@0: NS_ENSURE_TRUE(keys, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: *statep = PRIVATE_TO_JSVAL(keys); michael@0: michael@0: if (idp) { michael@0: *idp = INT_TO_JSID(keys->Length()); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsTArray *keys = michael@0: (nsTArray *)JSVAL_TO_PRIVATE(*statep); michael@0: michael@0: if (enum_op == JSENUMERATE_NEXT && keys->Length() != 0) { michael@0: nsString& key = keys->ElementAt(0); michael@0: JS::Rooted str(cx, JS_NewUCStringCopyN(cx, key.get(), key.Length())); michael@0: NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: JS::Rooted id(cx); michael@0: JS_StringToId(cx, str, &id); michael@0: *idp = id; michael@0: michael@0: keys->RemoveElementAt(0); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // destroy the keys array if we have no keys or if we're done michael@0: NS_ABORT_IF_FALSE(enum_op == JSENUMERATE_DESTROY || michael@0: (enum_op == JSENUMERATE_NEXT && keys->Length() == 0), michael@0: "Bad call from the JS engine"); michael@0: delete keys; michael@0: michael@0: *statep = JSVAL_NULL; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // nsIDOMEventListener::HandleEvent() 'this' converter helper michael@0: michael@0: NS_INTERFACE_MAP_BEGIN(nsEventListenerThisTranslator) michael@0: NS_INTERFACE_MAP_ENTRY(nsIXPCFunctionThisTranslator) michael@0: NS_INTERFACE_MAP_ENTRY(nsISupports) michael@0: NS_INTERFACE_MAP_END michael@0: michael@0: michael@0: NS_IMPL_ADDREF(nsEventListenerThisTranslator) michael@0: NS_IMPL_RELEASE(nsEventListenerThisTranslator) michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsEventListenerThisTranslator::TranslateThis(nsISupports *aInitialThis, michael@0: nsISupports **_retval) michael@0: { michael@0: nsCOMPtr event(do_QueryInterface(aInitialThis)); michael@0: NS_ENSURE_TRUE(event, NS_ERROR_UNEXPECTED); michael@0: michael@0: nsCOMPtr target = event->InternalDOMEvent()->GetCurrentTarget(); michael@0: target.forget(_retval); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMConstructorSH::PreCreate(nsISupports *nativeObj, JSContext *cx, michael@0: JSObject *aGlobalObj, JSObject **parentObj) michael@0: { michael@0: JS::Rooted globalObj(cx, aGlobalObj); michael@0: nsDOMConstructor *wrapped = static_cast(nativeObj); michael@0: michael@0: #ifdef DEBUG michael@0: { michael@0: nsCOMPtr is_constructor = michael@0: do_QueryInterface(nativeObj); michael@0: NS_ASSERTION(is_constructor, "How did we not get a constructor?"); michael@0: } michael@0: #endif michael@0: michael@0: return wrapped->PreCreate(cx, globalObj, parentObj); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMConstructorSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *aObj, jsid aId, JSObject **objp, michael@0: bool *_retval) michael@0: { michael@0: JS::Rooted obj(cx, aObj); michael@0: JS::Rooted id(cx, aId); michael@0: // For regular DOM constructors, we have our interface constants defined on michael@0: // us by nsWindowSH::GlobalResolve. However, XrayWrappers can't see these michael@0: // interface constants (as they look like expando properties) so we have to michael@0: // specially resolve those constants here, but only for Xray wrappers. michael@0: if (!ObjectIsNativeWrapper(cx, obj)) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: JS::Rooted nativePropsObj(cx, xpc::XrayUtils::GetNativePropertiesObject(cx, obj)); michael@0: nsDOMConstructor *wrapped = michael@0: static_cast(wrapper->Native()); michael@0: nsresult rv = wrapped->ResolveInterfaceConstants(cx, nativePropsObj); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Now re-lookup the ID to see if we should report back that we resolved the michael@0: // looked-for constant. Note that we don't have to worry about infinitely michael@0: // recurring back here because the Xray wrapper's holder object doesn't call michael@0: // NewResolve hooks. michael@0: bool found; michael@0: if (!JS_HasPropertyById(cx, nativePropsObj, id, &found)) { michael@0: *_retval = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (found) { michael@0: *objp = obj; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMConstructorSH::Call(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *aObj, const JS::CallArgs &args, bool *_retval) michael@0: { michael@0: JS::Rooted obj(cx, aObj); michael@0: MOZ_ASSERT(obj); michael@0: michael@0: nsDOMConstructor *wrapped = michael@0: static_cast(wrapper->Native()); michael@0: michael@0: #ifdef DEBUG michael@0: { michael@0: nsCOMPtr is_constructor = michael@0: do_QueryWrappedNative(wrapper); michael@0: NS_ASSERTION(is_constructor, "How did we not get a constructor?"); michael@0: } michael@0: #endif michael@0: michael@0: return wrapped->Construct(wrapper, cx, obj, args, _retval); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMConstructorSH::Construct(nsIXPConnectWrappedNative *wrapper, JSContext *cx, michael@0: JSObject *aObj, const JS::CallArgs &args, bool *_retval) michael@0: { michael@0: JS::Rooted obj(cx, aObj); michael@0: MOZ_ASSERT(obj); michael@0: michael@0: nsDOMConstructor *wrapped = michael@0: static_cast(wrapper->Native()); michael@0: michael@0: #ifdef DEBUG michael@0: { michael@0: nsCOMPtr is_constructor = michael@0: do_QueryWrappedNative(wrapper); michael@0: NS_ASSERTION(is_constructor, "How did we not get a constructor?"); michael@0: } michael@0: #endif michael@0: michael@0: return wrapped->Construct(wrapper, cx, obj, args, _retval); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDOMConstructorSH::HasInstance(nsIXPConnectWrappedNative *wrapper, michael@0: JSContext *cx, JSObject *aObj, JS::Handle val, michael@0: bool *bp, bool *_retval) michael@0: { michael@0: JS::Rooted obj(cx, aObj); michael@0: nsDOMConstructor *wrapped = michael@0: static_cast(wrapper->Native()); michael@0: michael@0: #ifdef DEBUG michael@0: { michael@0: nsCOMPtr is_constructor = michael@0: do_QueryWrappedNative(wrapper); michael@0: NS_ASSERTION(is_constructor, "How did we not get a constructor?"); michael@0: } michael@0: #endif michael@0: michael@0: return wrapped->HasInstance(wrapper, cx, obj, val, bp, _retval); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNonDOMObjectSH::GetFlags(uint32_t *aFlags) michael@0: { michael@0: // This is NOT a DOM Object. Use this helper class for cases when you need michael@0: // to do something like implement nsISecurityCheckedComponent in a meaningful michael@0: // way. michael@0: *aFlags = nsIClassInfo::MAIN_THREAD_ONLY | nsIClassInfo::SINGLETON_CLASSINFO; michael@0: return NS_OK; michael@0: }