forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			2177 lines
		
	
	
	
		
			69 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			2177 lines
		
	
	
	
		
			69 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #include "mozilla/ArrayUtils.h"
 | |
| 
 | |
| #ifdef XP_WIN
 | |
| #undef GetClassName
 | |
| #endif
 | |
| 
 | |
| // JavaScript includes
 | |
| #include "jsapi.h"
 | |
| #include "jsfriendapi.h"
 | |
| #include "WrapperFactory.h"
 | |
| #include "AccessCheck.h"
 | |
| #include "XrayWrapper.h"
 | |
| 
 | |
| #include "xpcpublic.h"
 | |
| #include "xpcprivate.h"
 | |
| #include "XPCWrapper.h"
 | |
| 
 | |
| #include "mozilla/DOMEventTargetHelper.h"
 | |
| #include "mozilla/dom/RegisterBindings.h"
 | |
| 
 | |
| #include "nscore.h"
 | |
| #include "nsDOMClassInfo.h"
 | |
| #include "nsIDOMClassInfo.h"
 | |
| #include "nsCRT.h"
 | |
| #include "nsCRTGlue.h"
 | |
| #include "nsICategoryManager.h"
 | |
| #include "nsIComponentRegistrar.h"
 | |
| #include "nsXPCOM.h"
 | |
| #include "nsISimpleEnumerator.h"
 | |
| #include "nsISupportsPrimitives.h"
 | |
| #include "nsIXPConnect.h"
 | |
| #include "xptcall.h"
 | |
| #include "nsTArray.h"
 | |
| 
 | |
| // General helper includes
 | |
| #include "nsGlobalWindow.h"
 | |
| #include "nsIContent.h"
 | |
| #include "nsIDocument.h"
 | |
| #include "nsIDOMDocument.h"
 | |
| #include "nsIDOMEvent.h"
 | |
| #include "nsIDOMEventListener.h"
 | |
| #include "nsContentUtils.h"
 | |
| #include "nsIDOMGlobalPropertyInitializer.h"
 | |
| #include "mozilla/Attributes.h"
 | |
| #include "mozilla/Telemetry.h"
 | |
| 
 | |
| // Window scriptable helper includes
 | |
| #include "nsScriptNameSpaceManager.h"
 | |
| 
 | |
| // DOM base includes
 | |
| #include "nsIDOMWindow.h"
 | |
| #include "nsPIDOMWindow.h"
 | |
| #include "nsIDOMConstructor.h"
 | |
| 
 | |
| // DOM core includes
 | |
| #include "nsError.h"
 | |
| #include "nsIDOMXULButtonElement.h"
 | |
| #include "nsIDOMXULCheckboxElement.h"
 | |
| #include "nsIDOMXULPopupElement.h"
 | |
| 
 | |
| // Event related includes
 | |
| #include "nsIDOMEventTarget.h"
 | |
| 
 | |
| // CSS related includes
 | |
| #include "nsCSSRules.h"
 | |
| #include "nsIDOMCSSRule.h"
 | |
| #include "nsMemory.h"
 | |
| 
 | |
| // includes needed for the prototype chain interfaces
 | |
| #include "nsIDOMCSSKeyframeRule.h"
 | |
| #include "nsIDOMCSSKeyframesRule.h"
 | |
| #include "nsIDOMCSSImportRule.h"
 | |
| #include "nsIDOMCSSMediaRule.h"
 | |
| #include "nsIDOMCSSFontFaceRule.h"
 | |
| #include "nsIDOMCSSMozDocumentRule.h"
 | |
| #include "nsIDOMCSSSupportsRule.h"
 | |
| #include "nsIDOMCSSCounterStyleRule.h"
 | |
| #include "nsIDOMCSSPageRule.h"
 | |
| #include "nsIDOMCSSStyleRule.h"
 | |
| #include "nsIDOMXULCommandDispatcher.h"
 | |
| #include "nsIControllers.h"
 | |
| #ifdef MOZ_XUL
 | |
| #include "nsITreeSelection.h"
 | |
| #include "nsITreeContentView.h"
 | |
| #include "nsITreeView.h"
 | |
| #include "nsIXULTemplateBuilder.h"
 | |
| #endif
 | |
| 
 | |
| #include "nsIEventListenerService.h"
 | |
| #include "nsIMessageManager.h"
 | |
| 
 | |
| #include "mozilla/dom/TouchEvent.h"
 | |
| 
 | |
| #include "nsWrapperCacheInlines.h"
 | |
| #include "mozilla/dom/HTMLCollectionBinding.h"
 | |
| 
 | |
| #ifdef MOZ_B2G_FM
 | |
| #include "FMRadio.h"
 | |
| #endif
 | |
| 
 | |
| #include "nsDebug.h"
 | |
| 
 | |
| #include "mozilla/dom/BindingUtils.h"
 | |
| #include "mozilla/Likely.h"
 | |
| #include "nsIInterfaceInfoManager.h"
 | |
| 
 | |
| #ifdef MOZ_TIME_MANAGER
 | |
| #include "TimeManager.h"
 | |
| #endif
 | |
| 
 | |
| using namespace mozilla;
 | |
| using namespace mozilla::dom;
 | |
| 
 | |
| // NOTE: DEFAULT_SCRIPTABLE_FLAGS and DOM_DEFAULT_SCRIPTABLE_FLAGS
 | |
| //       are defined in nsIDOMClassInfo.h.
 | |
| 
 | |
| #define DOMCLASSINFO_STANDARD_FLAGS                                           \
 | |
|   (nsIClassInfo::MAIN_THREAD_ONLY |                                           \
 | |
|    nsIClassInfo::DOM_OBJECT       |                                           \
 | |
|    nsIClassInfo::SINGLETON_CLASSINFO)
 | |
| 
 | |
| 
 | |
| #ifdef DEBUG
 | |
| #define NS_DEFINE_CLASSINFO_DATA_DEBUG(_class)                                \
 | |
|     eDOMClassInfo_##_class##_id,
 | |
| #else
 | |
| #define NS_DEFINE_CLASSINFO_DATA_DEBUG(_class)                                \
 | |
|   // nothing
 | |
| #endif
 | |
| 
 | |
| #define NS_DEFINE_CLASSINFO_DATA_HELPER(_class, _helper, _flags,              \
 | |
|                                         _chromeOnly, _allowXBL)               \
 | |
|   { #_class,                                                                  \
 | |
|     nullptr,                                                                  \
 | |
|     _helper::doCreate,                                                        \
 | |
|     nullptr,                                                                  \
 | |
|     nullptr,                                                                  \
 | |
|     nullptr,                                                                  \
 | |
|     _flags,                                                                   \
 | |
|     true,                                                                     \
 | |
|     _chromeOnly,                                                              \
 | |
|     _allowXBL,                                                                \
 | |
|     false,                                                                    \
 | |
|     NS_DEFINE_CLASSINFO_DATA_DEBUG(_class)                                    \
 | |
|   },
 | |
| 
 | |
| #define NS_DEFINE_CLASSINFO_DATA(_class, _helper, _flags)                     \
 | |
|   NS_DEFINE_CLASSINFO_DATA_HELPER(_class, _helper, _flags, false, false)
 | |
| 
 | |
| #define NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(_class, _helper, _flags)         \
 | |
|   NS_DEFINE_CLASSINFO_DATA_HELPER(_class, _helper, _flags, true, false)
 | |
| 
 | |
| #define NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(_class, _helper, _flags)          \
 | |
|   NS_DEFINE_CLASSINFO_DATA_HELPER(_class, _helper, _flags, true, true)
 | |
| 
 | |
| 
 | |
| // This list of NS_DEFINE_CLASSINFO_DATA macros is what gives the DOM
 | |
| // classes their correct behavior when used through XPConnect. The
 | |
| // arguments that are passed to NS_DEFINE_CLASSINFO_DATA are
 | |
| //
 | |
| // 1. Class name as it should appear in JavaScript, this name is also
 | |
| //    used to find the id of the class in nsDOMClassInfo
 | |
| //    (i.e. e<classname>_id)
 | |
| // 2. Scriptable helper class
 | |
| // 3. nsIClassInfo/nsIXPCScriptable flags (i.e. for GetScriptableFlags)
 | |
| 
 | |
| static nsDOMClassInfoData sClassInfoData[] = {
 | |
|   // Base classes
 | |
| 
 | |
|   NS_DEFINE_CLASSINFO_DATA(DOMPrototype, nsDOMConstructorSH,
 | |
|                            DOM_BASE_SCRIPTABLE_FLAGS |
 | |
|                            nsIXPCScriptable::WANT_PRECREATE |
 | |
|                            nsIXPCScriptable::WANT_RESOLVE |
 | |
|                            nsIXPCScriptable::WANT_HASINSTANCE |
 | |
|                            nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE)
 | |
|   NS_DEFINE_CLASSINFO_DATA(DOMConstructor, nsDOMConstructorSH,
 | |
|                            DOM_BASE_SCRIPTABLE_FLAGS |
 | |
|                            nsIXPCScriptable::WANT_PRECREATE |
 | |
|                            nsIXPCScriptable::WANT_RESOLVE |
 | |
|                            nsIXPCScriptable::WANT_HASINSTANCE |
 | |
|                            nsIXPCScriptable::WANT_CALL |
 | |
|                            nsIXPCScriptable::WANT_CONSTRUCT |
 | |
|                            nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE)
 | |
| 
 | |
|   // Misc Core related classes
 | |
| 
 | |
|   // CSS classes
 | |
|   NS_DEFINE_CLASSINFO_DATA(CSSStyleRule, nsDOMGenericSH,
 | |
|                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 | |
|   NS_DEFINE_CLASSINFO_DATA(CSSImportRule, nsDOMGenericSH,
 | |
|                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 | |
|   NS_DEFINE_CLASSINFO_DATA(CSSMediaRule, nsDOMGenericSH,
 | |
|                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 | |
|   NS_DEFINE_CLASSINFO_DATA(CSSNameSpaceRule, nsDOMGenericSH,
 | |
|                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 | |
| 
 | |
|   // XUL classes
 | |
| #ifdef MOZ_XUL
 | |
|   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULCommandDispatcher, nsDOMGenericSH,
 | |
|                                       DOM_DEFAULT_SCRIPTABLE_FLAGS)
 | |
| #endif
 | |
|   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULControllers, nsNonDOMObjectSH,
 | |
|                                       DEFAULT_SCRIPTABLE_FLAGS)
 | |
| #ifdef MOZ_XUL
 | |
|   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(TreeSelection, nsDOMGenericSH,
 | |
|                                       DEFAULT_SCRIPTABLE_FLAGS)
 | |
|   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(TreeContentView, nsDOMGenericSH,
 | |
|                                       DEFAULT_SCRIPTABLE_FLAGS)
 | |
| #endif
 | |
| 
 | |
| #ifdef MOZ_XUL
 | |
|   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULTemplateBuilder, nsDOMGenericSH,
 | |
|                                       DEFAULT_SCRIPTABLE_FLAGS)
 | |
| 
 | |
|   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULTreeBuilder, nsDOMGenericSH,
 | |
|                                       DEFAULT_SCRIPTABLE_FLAGS)
 | |
| #endif
 | |
| 
 | |
|   NS_DEFINE_CLASSINFO_DATA(CSSMozDocumentRule, nsDOMGenericSH,
 | |
|                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 | |
| 
 | |
|   NS_DEFINE_CLASSINFO_DATA(CSSSupportsRule, nsDOMGenericSH,
 | |
|                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 | |
| 
 | |
|   NS_DEFINE_CLASSINFO_DATA(CSSFontFaceRule, nsDOMGenericSH,
 | |
|                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 | |
| 
 | |
|   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ContentFrameMessageManager,
 | |
|                                        nsMessageManagerSH<nsEventTargetSH>,
 | |
|                                        DOM_DEFAULT_SCRIPTABLE_FLAGS |
 | |
|                                        nsIXPCScriptable::WANT_ENUMERATE |
 | |
|                                        nsIXPCScriptable::IS_GLOBAL_OBJECT)
 | |
|   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ContentProcessMessageManager,
 | |
|                                        nsMessageManagerSH<nsDOMGenericSH>,
 | |
|                                        DOM_DEFAULT_SCRIPTABLE_FLAGS |
 | |
|                                        nsIXPCScriptable::WANT_ENUMERATE |
 | |
|                                        nsIXPCScriptable::IS_GLOBAL_OBJECT)
 | |
|   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ChromeMessageBroadcaster, nsDOMGenericSH,
 | |
|                                        DOM_DEFAULT_SCRIPTABLE_FLAGS)
 | |
|   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ChromeMessageSender, nsDOMGenericSH,
 | |
|                                        DOM_DEFAULT_SCRIPTABLE_FLAGS)
 | |
| 
 | |
| 
 | |
|   NS_DEFINE_CLASSINFO_DATA(CSSKeyframeRule, nsDOMGenericSH,
 | |
|                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 | |
|   NS_DEFINE_CLASSINFO_DATA(CSSKeyframesRule, nsDOMGenericSH,
 | |
|                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 | |
| 
 | |
|   NS_DEFINE_CLASSINFO_DATA(CSSCounterStyleRule, nsDOMGenericSH,
 | |
|                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 | |
| 
 | |
|   NS_DEFINE_CLASSINFO_DATA(CSSPageRule, nsDOMGenericSH,
 | |
|                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 | |
| 
 | |
|   NS_DEFINE_CLASSINFO_DATA(CSSFontFeatureValuesRule, nsDOMGenericSH,
 | |
|                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 | |
| 
 | |
|   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULControlElement, nsDOMGenericSH,
 | |
|                                       DOM_DEFAULT_SCRIPTABLE_FLAGS)
 | |
|   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULLabeledControlElement, nsDOMGenericSH,
 | |
|                                       DOM_DEFAULT_SCRIPTABLE_FLAGS)
 | |
|   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULButtonElement, nsDOMGenericSH,
 | |
|                                       DOM_DEFAULT_SCRIPTABLE_FLAGS)
 | |
|   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULCheckboxElement, nsDOMGenericSH,
 | |
|                                       DOM_DEFAULT_SCRIPTABLE_FLAGS)
 | |
|   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULPopupElement, nsDOMGenericSH,
 | |
|                                       DOM_DEFAULT_SCRIPTABLE_FLAGS)
 | |
| };
 | |
| 
 | |
| nsIXPConnect *nsDOMClassInfo::sXPConnect = nullptr;
 | |
| bool nsDOMClassInfo::sIsInitialized = false;
 | |
| 
 | |
| 
 | |
| jsid nsDOMClassInfo::sConstructor_id     = JSID_VOID;
 | |
| jsid nsDOMClassInfo::sWrappedJSObject_id = JSID_VOID;
 | |
| 
 | |
| static const JSClass *sObjectClass = nullptr;
 | |
| 
 | |
| /**
 | |
|  * Set our JSClass pointer for the Object class
 | |
|  */
 | |
| static void
 | |
| FindObjectClass(JSContext* cx, JSObject* aGlobalObject)
 | |
| {
 | |
|   NS_ASSERTION(!sObjectClass,
 | |
|                "Double set of sObjectClass");
 | |
|   JS::Rooted<JSObject*> obj(cx), proto(cx, aGlobalObject);
 | |
|   do {
 | |
|     obj = proto;
 | |
|     js::GetObjectProto(cx, obj, &proto);
 | |
|   } while (proto);
 | |
| 
 | |
|   sObjectClass = js::GetObjectJSClass(obj);
 | |
| }
 | |
| 
 | |
| // Helper to handle torn-down inner windows.
 | |
| static inline nsresult
 | |
| SetParentToWindow(nsGlobalWindow *win, JSObject **parent)
 | |
| {
 | |
|   MOZ_ASSERT(win);
 | |
|   MOZ_ASSERT(win->IsInnerWindow());
 | |
|   *parent = win->FastGetGlobalJSObject();
 | |
| 
 | |
|   if (MOZ_UNLIKELY(!*parent)) {
 | |
|     // The inner window has been torn down. The scope is dying, so don't create
 | |
|     // any new wrappers.
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| // static
 | |
| 
 | |
| nsISupports *
 | |
| nsDOMClassInfo::GetNative(nsIXPConnectWrappedNative *wrapper, JSObject *obj)
 | |
| {
 | |
|   return wrapper ? wrapper->Native() : static_cast<nsISupports*>(js::GetObjectPrivate(obj));
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| nsDOMClassInfo::DefineStaticJSVals()
 | |
| {
 | |
|   AutoJSAPI jsapi;
 | |
|   if (!jsapi.Init(xpc::UnprivilegedJunkScope())) {
 | |
|     return NS_ERROR_UNEXPECTED;
 | |
|   }
 | |
|   JSContext* cx = jsapi.cx();
 | |
| 
 | |
| #define SET_JSID_TO_STRING(_id, _cx, _str)                              \
 | |
|   if (JSString *str = ::JS_AtomizeAndPinString(_cx, _str))                             \
 | |
|       _id = INTERNED_STRING_TO_JSID(_cx, str);                                \
 | |
|   else                                                                        \
 | |
|       return NS_ERROR_OUT_OF_MEMORY;
 | |
| 
 | |
|   SET_JSID_TO_STRING(sConstructor_id,     cx, "constructor");
 | |
|   SET_JSID_TO_STRING(sWrappedJSObject_id, cx, "wrappedJSObject");
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| // static
 | |
| bool
 | |
| nsDOMClassInfo::ObjectIsNativeWrapper(JSContext* cx, JSObject* obj)
 | |
| {
 | |
|   return xpc::WrapperFactory::IsXrayWrapper(obj) &&
 | |
|          xpc::AccessCheck::wrapperSubsumes(obj);
 | |
| }
 | |
| 
 | |
| nsDOMClassInfo::nsDOMClassInfo(nsDOMClassInfoData* aData) : mData(aData)
 | |
| {
 | |
| }
 | |
| 
 | |
| NS_IMPL_ADDREF(nsDOMClassInfo)
 | |
| NS_IMPL_RELEASE(nsDOMClassInfo)
 | |
| 
 | |
| NS_INTERFACE_MAP_BEGIN(nsDOMClassInfo)
 | |
|   if (aIID.Equals(NS_GET_IID(nsXPCClassInfo)))
 | |
|     foundInterface = static_cast<nsIClassInfo*>(
 | |
|                                     static_cast<nsXPCClassInfo*>(this));
 | |
|   else
 | |
|   NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable)
 | |
|   NS_INTERFACE_MAP_ENTRY(nsIClassInfo)
 | |
|   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIClassInfo)
 | |
| NS_INTERFACE_MAP_END
 | |
| 
 | |
| 
 | |
| static const JSClass sDOMConstructorProtoClass = {
 | |
|   "DOM Constructor.prototype", 0
 | |
| };
 | |
| 
 | |
| 
 | |
| static const char *
 | |
| CutPrefix(const char *aName) {
 | |
|   static const char prefix_nsIDOM[] = "nsIDOM";
 | |
|   static const char prefix_nsI[]    = "nsI";
 | |
| 
 | |
|   if (strncmp(aName, prefix_nsIDOM, sizeof(prefix_nsIDOM) - 1) == 0) {
 | |
|     return aName + sizeof(prefix_nsIDOM) - 1;
 | |
|   }
 | |
| 
 | |
|   if (strncmp(aName, prefix_nsI, sizeof(prefix_nsI) - 1) == 0) {
 | |
|     return aName + sizeof(prefix_nsI) - 1;
 | |
|   }
 | |
| 
 | |
|   return aName;
 | |
| }
 | |
| 
 | |
| // static
 | |
| nsresult
 | |
| nsDOMClassInfo::RegisterClassProtos(int32_t aClassInfoID)
 | |
| {
 | |
|   nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
 | |
|   NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
 | |
|   bool found_old;
 | |
| 
 | |
|   const nsIID *primary_iid = sClassInfoData[aClassInfoID].mProtoChainInterface;
 | |
| 
 | |
|   if (!primary_iid || primary_iid == &NS_GET_IID(nsISupports)) {
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsIInterfaceInfoManager>
 | |
|     iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
 | |
|   NS_ENSURE_TRUE(iim, NS_ERROR_NOT_AVAILABLE);
 | |
| 
 | |
|   nsCOMPtr<nsIInterfaceInfo> if_info;
 | |
|   bool first = true;
 | |
| 
 | |
|   iim->GetInfoForIID(primary_iid, getter_AddRefs(if_info));
 | |
| 
 | |
|   while (if_info) {
 | |
|     const nsIID *iid = nullptr;
 | |
| 
 | |
|     if_info->GetIIDShared(&iid);
 | |
|     NS_ENSURE_TRUE(iid, NS_ERROR_UNEXPECTED);
 | |
| 
 | |
|     if (iid->Equals(NS_GET_IID(nsISupports))) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     const char *name = nullptr;
 | |
|     if_info->GetNameShared(&name);
 | |
|     NS_ENSURE_TRUE(name, NS_ERROR_UNEXPECTED);
 | |
| 
 | |
|     nameSpaceManager->RegisterClassProto(CutPrefix(name), iid, &found_old);
 | |
| 
 | |
|     if (first) {
 | |
|       first = false;
 | |
|     } else if (found_old) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     nsCOMPtr<nsIInterfaceInfo> tmp(if_info);
 | |
|     tmp->GetParent(getter_AddRefs(if_info));
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| #define _DOM_CLASSINFO_MAP_BEGIN(_class, _ifptr, _has_class_if)               \
 | |
|   {                                                                           \
 | |
|     nsDOMClassInfoData &d = sClassInfoData[eDOMClassInfo_##_class##_id];      \
 | |
|     d.mProtoChainInterface = _ifptr;                                          \
 | |
|     d.mHasClassInterface = _has_class_if;                                     \
 | |
|     static const nsIID *interface_list[] = {
 | |
| 
 | |
| #define DOM_CLASSINFO_MAP_BEGIN(_class, _interface)                           \
 | |
|   _DOM_CLASSINFO_MAP_BEGIN(_class, &NS_GET_IID(_interface), true)
 | |
| 
 | |
| #define DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(_class, _interface)               \
 | |
|   _DOM_CLASSINFO_MAP_BEGIN(_class, &NS_GET_IID(_interface), false)
 | |
| 
 | |
| #define DOM_CLASSINFO_MAP_ENTRY(_if)                                          \
 | |
|       &NS_GET_IID(_if),
 | |
| 
 | |
| #define DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(_if, _cond)                       \
 | |
|       (_cond) ? &NS_GET_IID(_if) : nullptr,
 | |
| 
 | |
| #define DOM_CLASSINFO_MAP_END                                                 \
 | |
|       nullptr                                                                  \
 | |
|     };                                                                        \
 | |
|                                                                               \
 | |
|     /* Compact the interface list */                                          \
 | |
|     size_t count = ArrayLength(interface_list);                               \
 | |
|     /* count is the number of array entries, which is one greater than the */ \
 | |
|     /* number of interfaces due to the terminating null */                    \
 | |
|     for (size_t i = 0; i < count - 1; ++i) {                                  \
 | |
|       if (!interface_list[i]) {                                               \
 | |
|         /* We are moving the element at index i+1 and successors, */          \
 | |
|         /* so we must move only count - (i+1) elements total. */              \
 | |
|         memmove(&interface_list[i], &interface_list[i+1],                     \
 | |
|                 sizeof(nsIID*) * (count - (i+1)));                            \
 | |
|         /* Make sure to examine the new pointer we ended up with at this */   \
 | |
|         /* slot, since it may be null too */                                  \
 | |
|         --i;                                                                  \
 | |
|         --count;                                                              \
 | |
|       }                                                                       \
 | |
|     }                                                                         \
 | |
|                                                                               \
 | |
|     d.mInterfaces = interface_list;                                           \
 | |
|   }
 | |
| 
 | |
| nsresult
 | |
| nsDOMClassInfo::Init()
 | |
| {
 | |
|   /* Errors that can trigger early returns are done first,
 | |
|      otherwise nsDOMClassInfo is left in a half inited state. */
 | |
|   static_assert(sizeof(uintptr_t) == sizeof(void*),
 | |
|                 "BAD! You'll need to adjust the size of uintptr_t to the "
 | |
|                 "size of a pointer on your platform.");
 | |
| 
 | |
|   NS_ENSURE_TRUE(!sIsInitialized, NS_ERROR_ALREADY_INITIALIZED);
 | |
| 
 | |
|   nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
 | |
|   NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
 | |
| 
 | |
|   NS_ADDREF(sXPConnect = nsContentUtils::XPConnect());
 | |
| 
 | |
|   nsCOMPtr<nsIXPCFunctionThisTranslator> elt = new nsEventListenerThisTranslator();
 | |
|   sXPConnect->SetFunctionThisTranslator(NS_GET_IID(nsIDOMEventListener), elt);
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(DOMPrototype, nsIDOMDOMConstructor)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMConstructor)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN(DOMConstructor, nsIDOMDOMConstructor)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMConstructor)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN(CSSStyleRule, nsIDOMCSSStyleRule)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSStyleRule)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN(CSSImportRule, nsIDOMCSSImportRule)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSImportRule)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN(CSSMediaRule, nsIDOMCSSMediaRule)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSMediaRule)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(CSSNameSpaceRule, nsIDOMCSSRule)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSRule)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
| #ifdef MOZ_XUL
 | |
|   DOM_CLASSINFO_MAP_BEGIN(XULCommandDispatcher, nsIDOMXULCommandDispatcher)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULCommandDispatcher)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| #endif
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULControllers, nsIControllers)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIControllers)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
| #ifdef MOZ_XUL
 | |
|   DOM_CLASSINFO_MAP_BEGIN(TreeSelection, nsITreeSelection)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsITreeSelection)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN(TreeContentView, nsITreeContentView)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsITreeContentView)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsITreeView)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| #endif
 | |
| 
 | |
| #ifdef MOZ_XUL
 | |
|   DOM_CLASSINFO_MAP_BEGIN(XULTemplateBuilder, nsIXULTemplateBuilder)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIXULTemplateBuilder)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN(XULTreeBuilder, nsIXULTreeBuilder)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIXULTreeBuilder)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIXULTemplateBuilder)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsITreeView)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| #endif
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN(CSSMozDocumentRule, nsIDOMCSSMozDocumentRule)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSMozDocumentRule)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN(CSSSupportsRule, nsIDOMCSSSupportsRule)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSSupportsRule)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN(CSSFontFaceRule, nsIDOMCSSFontFaceRule)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSFontFaceRule)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ContentFrameMessageManager, nsISupports)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIMessageSender)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsISyncMessageSender)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIContentFrameMessageManager)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ContentProcessMessageManager, nsISupports)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIMessageSender)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsISyncMessageSender)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIContentProcessMessageManager)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ChromeMessageBroadcaster, nsISupports)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIFrameScriptLoader)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIProcessScriptLoader)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIGlobalProcessScriptLoader)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIMessageBroadcaster)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ChromeMessageSender, nsISupports)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIProcessChecker)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIFrameScriptLoader)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIProcessScriptLoader)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIMessageSender)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN(CSSKeyframeRule, nsIDOMCSSKeyframeRule)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSKeyframeRule)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN(CSSKeyframesRule, nsIDOMCSSKeyframesRule)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSKeyframesRule)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN(CSSCounterStyleRule, nsIDOMCSSCounterStyleRule)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSCounterStyleRule)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN(CSSPageRule, nsIDOMCSSPageRule)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSPageRule)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN(CSSFontFeatureValuesRule, nsIDOMCSSFontFeatureValuesRule)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSFontFeatureValuesRule)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULControlElement, nsIDOMXULControlElement)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULControlElement)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULLabeledControlElement, nsIDOMXULLabeledControlElement)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULLabeledControlElement)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULButtonElement, nsIDOMXULButtonElement)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULButtonElement)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULCheckboxElement, nsIDOMXULCheckboxElement)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULCheckboxElement)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
|   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULPopupElement, nsIDOMXULPopupElement)
 | |
|     DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULPopupElement)
 | |
|   DOM_CLASSINFO_MAP_END
 | |
| 
 | |
|   static_assert(MOZ_ARRAY_LENGTH(sClassInfoData) == eDOMClassInfoIDCount,
 | |
|                 "The number of items in sClassInfoData doesn't match the "
 | |
|                 "number of nsIDOMClassInfo ID's, this is bad! Fix it!");
 | |
| 
 | |
| #ifdef DEBUG
 | |
|   for (size_t i = 0; i < eDOMClassInfoIDCount; i++) {
 | |
|     if (!sClassInfoData[i].mConstructorFptr ||
 | |
|         sClassInfoData[i].mDebugID != i) {
 | |
|       MOZ_CRASH("Class info data out of sync, you forgot to update "
 | |
|                 "nsDOMClassInfo.h and nsDOMClassInfo.cpp! Fix this, "
 | |
|                 "mozilla will not work without this fixed!");
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   for (size_t i = 0; i < eDOMClassInfoIDCount; i++) {
 | |
|     if (!sClassInfoData[i].mInterfaces) {
 | |
|       MOZ_CRASH("Class info data without an interface list! Fix this, "
 | |
|                 "mozilla will not work without this fixed!");
 | |
|      }
 | |
|    }
 | |
| #endif
 | |
| 
 | |
|   // Initialize static JSString's
 | |
|   DefineStaticJSVals();
 | |
| 
 | |
|   int32_t i;
 | |
| 
 | |
|   for (i = 0; i < eDOMClassInfoIDCount; ++i) {
 | |
|     if (i == eDOMClassInfo_DOMPrototype_id) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     nsDOMClassInfoData& data = sClassInfoData[i];
 | |
|     nameSpaceManager->RegisterClassName(data.mName, i, data.mChromeOnly,
 | |
|                                         data.mAllowXBL, &data.mNameUTF16);
 | |
|   }
 | |
| 
 | |
|   for (i = 0; i < eDOMClassInfoIDCount; ++i) {
 | |
|     RegisterClassProtos(i);
 | |
|   }
 | |
| 
 | |
|   sIsInitialized = true;
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMClassInfo::GetInterfaces(uint32_t *aCount, nsIID ***aArray)
 | |
| {
 | |
|   uint32_t count = 0;
 | |
| 
 | |
|   while (mData->mInterfaces[count]) {
 | |
|     count++;
 | |
|   }
 | |
| 
 | |
|   *aCount = count;
 | |
| 
 | |
|   if (!count) {
 | |
|     *aArray = nullptr;
 | |
| 
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   *aArray = static_cast<nsIID **>(moz_xmalloc(count * sizeof(nsIID *)));
 | |
|   NS_ENSURE_TRUE(*aArray, NS_ERROR_OUT_OF_MEMORY);
 | |
| 
 | |
|   uint32_t i;
 | |
|   for (i = 0; i < count; i++) {
 | |
|     nsIID *iid = static_cast<nsIID *>(nsMemory::Clone(mData->mInterfaces[i],
 | |
|                                                          sizeof(nsIID)));
 | |
| 
 | |
|     if (!iid) {
 | |
|       NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, *aArray);
 | |
| 
 | |
|       return NS_ERROR_OUT_OF_MEMORY;
 | |
|     }
 | |
| 
 | |
|     *((*aArray) + i) = iid;
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMClassInfo::GetScriptableHelper(nsIXPCScriptable **_retval)
 | |
| {
 | |
|   nsCOMPtr<nsIXPCScriptable> rval = this;
 | |
|   rval.forget(_retval);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMClassInfo::GetContractID(char **aContractID)
 | |
| {
 | |
|   *aContractID = nullptr;
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMClassInfo::GetClassDescription(char **aClassDescription)
 | |
| {
 | |
|   return GetClassName(aClassDescription);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMClassInfo::GetClassID(nsCID **aClassID)
 | |
| {
 | |
|   *aClassID = nullptr;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMClassInfo::GetClassIDNoAlloc(nsCID *aClassID)
 | |
| {
 | |
|   return NS_ERROR_NOT_AVAILABLE;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMClassInfo::GetFlags(uint32_t *aFlags)
 | |
| {
 | |
|   *aFlags = DOMCLASSINFO_STANDARD_FLAGS;
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| // nsIXPCScriptable
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMClassInfo::GetClassName(char **aClassName)
 | |
| {
 | |
|   *aClassName = NS_strdup(mData->mName);
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| // virtual
 | |
| uint32_t
 | |
| nsDOMClassInfo::GetScriptableFlags()
 | |
| {
 | |
|   return mData->mScriptableFlags;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMClassInfo::PreCreate(nsISupports *nativeObj, JSContext *cx,
 | |
|                           JSObject *globalObj, JSObject **parentObj)
 | |
| {
 | |
|   *parentObj = globalObj;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMClassInfo::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
 | |
|                             JSObject *obj, jsid id, JS::Handle<JS::Value> val,
 | |
|                             bool *_retval)
 | |
| {
 | |
|   NS_WARNING("nsDOMClassInfo::AddProperty Don't call me!");
 | |
| 
 | |
|   return NS_ERROR_UNEXPECTED;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMClassInfo::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
 | |
|                             JSObject *obj, jsid id, JS::Value *vp,
 | |
|                             bool *_retval)
 | |
| {
 | |
|   NS_WARNING("nsDOMClassInfo::GetProperty Don't call me!");
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMClassInfo::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
 | |
|                             JSObject *obj, jsid id, JS::Value *vp,
 | |
|                             bool *_retval)
 | |
| {
 | |
|   NS_WARNING("nsDOMClassInfo::SetProperty Don't call me!");
 | |
| 
 | |
|   return NS_ERROR_UNEXPECTED;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMClassInfo::Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
 | |
|                           JSObject *obj, bool *_retval)
 | |
| {
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMClassInfo::NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
 | |
|                              JSObject *obj, JS::AutoIdVector &properties,
 | |
|                              bool *_retval)
 | |
| {
 | |
|   NS_WARNING("nsDOMClassInfo::NewEnumerate Don't call me!");
 | |
| 
 | |
|   return NS_ERROR_UNEXPECTED;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMClassInfo::Resolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
 | |
|                         JSObject *aObj, jsid aId, bool *resolvedp, bool *_retval)
 | |
| {
 | |
|   JS::Rooted<JSObject*> obj(cx, aObj);
 | |
|   JS::Rooted<jsid> id(cx, aId);
 | |
| 
 | |
|   if (id != sConstructor_id) {
 | |
|     *resolvedp = false;
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   JS::Rooted<JSObject*> global(cx, ::JS_GetGlobalForObject(cx, obj));
 | |
| 
 | |
|   JS::Rooted<JS::PropertyDescriptor> desc(cx);
 | |
|   if (!JS_GetPropertyDescriptor(cx, global, mData->mName, &desc)) {
 | |
|     return NS_ERROR_UNEXPECTED;
 | |
|   }
 | |
| 
 | |
|   if (desc.object() && !desc.hasGetterOrSetter() && desc.value().isObject()) {
 | |
|     // If val is not an (non-null) object there either is no
 | |
|     // constructor for this class, or someone messed with
 | |
|     // window.classname, just fall through and let the JS engine
 | |
|     // return the Object constructor.
 | |
|     if (!::JS_DefinePropertyById(cx, obj, id, desc.value(),
 | |
|                                  JSPROP_ENUMERATE,
 | |
|                                  JS_STUBGETTER, JS_STUBSETTER)) {
 | |
|       return NS_ERROR_UNEXPECTED;
 | |
|     }
 | |
| 
 | |
|     *resolvedp = true;
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMClassInfo::Finalize(nsIXPConnectWrappedNative *wrapper, JSFreeOp *fop,
 | |
|                          JSObject *obj)
 | |
| {
 | |
|   NS_WARNING("nsDOMClassInfo::Finalize Don't call me!");
 | |
| 
 | |
|   return NS_ERROR_UNEXPECTED;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMClassInfo::Call(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
 | |
|                      JSObject *obj, const JS::CallArgs &args, bool *_retval)
 | |
| {
 | |
|   NS_WARNING("nsDOMClassInfo::Call Don't call me!");
 | |
| 
 | |
|   return NS_ERROR_UNEXPECTED;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMClassInfo::Construct(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
 | |
|                           JSObject *obj, const JS::CallArgs &args,
 | |
|                           bool *_retval)
 | |
| {
 | |
|   NS_WARNING("nsDOMClassInfo::Construct Don't call me!");
 | |
| 
 | |
|   return NS_ERROR_UNEXPECTED;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMClassInfo::HasInstance(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
 | |
|                             JSObject *obj, JS::Handle<JS::Value> val, bool *bp,
 | |
|                             bool *_retval)
 | |
| {
 | |
|   NS_WARNING("nsDOMClassInfo::HasInstance Don't call me!");
 | |
| 
 | |
|   return NS_ERROR_UNEXPECTED;
 | |
| }
 | |
| 
 | |
| static nsresult
 | |
| ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx,
 | |
|                  JS::Handle<JSObject*> obj, const char16_t *name,
 | |
|                  const nsDOMClassInfoData *ci_data,
 | |
|                  const nsGlobalNameStruct *name_struct,
 | |
|                  nsScriptNameSpaceManager *nameSpaceManager,
 | |
|                  JSObject *dot_prototype,
 | |
|                  JS::MutableHandle<JS::PropertyDescriptor> ctorDesc);
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMClassInfo::PostCreatePrototype(JSContext * cx, JSObject * aProto)
 | |
| {
 | |
|   JS::Rooted<JSObject*> proto(cx, aProto);
 | |
| 
 | |
|   // This is called before any other location that requires
 | |
|   // sObjectClass, so compute it here. We assume that nobody has had a
 | |
|   // chance to monkey around with proto's prototype chain before this.
 | |
|   if (!sObjectClass) {
 | |
|     FindObjectClass(cx, proto);
 | |
|     NS_ASSERTION(sObjectClass && !strcmp(sObjectClass->name, "Object"),
 | |
|                  "Incorrect object class!");
 | |
|   }
 | |
| 
 | |
| #ifdef DEBUG
 | |
|     JS::Rooted<JSObject*> proto2(cx);
 | |
|     JS_GetPrototype(cx, proto, &proto2);
 | |
|     NS_ASSERTION(proto2 && JS_GetClass(proto2) == sObjectClass,
 | |
|                  "Hmm, somebody did something evil?");
 | |
| #endif
 | |
| 
 | |
| #ifdef DEBUG
 | |
|   if (mData->mHasClassInterface && mData->mProtoChainInterface &&
 | |
|       mData->mProtoChainInterface != &NS_GET_IID(nsISupports)) {
 | |
|     nsCOMPtr<nsIInterfaceInfoManager>
 | |
|       iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
 | |
| 
 | |
|     if (iim) {
 | |
|       nsCOMPtr<nsIInterfaceInfo> if_info;
 | |
|       iim->GetInfoForIID(mData->mProtoChainInterface,
 | |
|                          getter_AddRefs(if_info));
 | |
| 
 | |
|       if (if_info) {
 | |
|         nsXPIDLCString name;
 | |
|         if_info->GetName(getter_Copies(name));
 | |
|         NS_ASSERTION(nsCRT::strcmp(CutPrefix(name), mData->mName) == 0,
 | |
|                      "Class name and proto chain interface name mismatch!");
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   // Make prototype delegation work correctly. Consider if a site sets
 | |
|   // HTMLElement.prototype.foopy = function () { ... } Now, calling
 | |
|   // document.body.foopy() needs to ensure that looking up foopy on
 | |
|   // document.body's prototype will find the right function.
 | |
|   JS::Rooted<JSObject*> global(cx, ::JS_GetGlobalForObject(cx, proto));
 | |
| 
 | |
|   // Only do this if the global object is a window.
 | |
|   // XXX Is there a better way to check this?
 | |
|   nsISupports *globalNative = XPConnect()->GetNativeOfWrapper(cx, global);
 | |
|   nsCOMPtr<nsPIDOMWindowInner> piwin = do_QueryInterface(globalNative);
 | |
|   if (!piwin) {
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   nsGlobalWindow *win = nsGlobalWindow::Cast(piwin);
 | |
|   if (win->IsClosedOrClosing()) {
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   // If the window is in a different compartment than the global object, then
 | |
|   // it's likely that global is a sandbox object whose prototype is a window.
 | |
|   // Don't do anything in this case.
 | |
|   if (win->FastGetGlobalJSObject() &&
 | |
|       js::GetObjectCompartment(global) != js::GetObjectCompartment(win->FastGetGlobalJSObject())) {
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   // Don't overwrite a property set by content.
 | |
|   bool contentDefinedProperty;
 | |
|   if (!::JS_AlreadyHasOwnUCProperty(cx, global, reinterpret_cast<const char16_t*>(mData->mNameUTF16),
 | |
|                                     NS_strlen(mData->mNameUTF16),
 | |
|                                     &contentDefinedProperty)) {
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
 | |
|   NS_ENSURE_TRUE(nameSpaceManager, NS_OK);
 | |
| 
 | |
|   JS::Rooted<JS::PropertyDescriptor> desc(cx);
 | |
|   nsresult rv = ResolvePrototype(sXPConnect, win, cx, global, mData->mNameUTF16,
 | |
|                                  mData, nullptr, nameSpaceManager, proto,
 | |
|                                  &desc);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
|   if (!contentDefinedProperty && desc.object() && !desc.value().isUndefined()) {
 | |
|     desc.attributesRef() |= JSPROP_RESOLVING;
 | |
|     if (!JS_DefineUCProperty(cx, global, mData->mNameUTF16,
 | |
|                              NS_strlen(mData->mNameUTF16), desc)) {
 | |
|       return NS_ERROR_UNEXPECTED;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| // static
 | |
| nsIClassInfo *
 | |
| NS_GetDOMClassInfoInstance(nsDOMClassInfoID aID)
 | |
| {
 | |
|   if (aID >= eDOMClassInfoIDCount) {
 | |
|     NS_ERROR("Bad ID!");
 | |
| 
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   nsresult rv = RegisterDOMNames();
 | |
|   NS_ENSURE_SUCCESS(rv, nullptr);
 | |
| 
 | |
|   if (!sClassInfoData[aID].mCachedClassInfo) {
 | |
|     nsDOMClassInfoData& data = sClassInfoData[aID];
 | |
| 
 | |
|     data.mCachedClassInfo = data.mConstructorFptr(&data);
 | |
|     NS_ENSURE_TRUE(data.mCachedClassInfo, nullptr);
 | |
| 
 | |
|     NS_ADDREF(data.mCachedClassInfo);
 | |
|   }
 | |
| 
 | |
|   return sClassInfoData[aID].mCachedClassInfo;
 | |
| }
 | |
| 
 | |
| // static
 | |
| void
 | |
| nsDOMClassInfo::ShutDown()
 | |
| {
 | |
|   if (sClassInfoData[0].mConstructorFptr) {
 | |
|     uint32_t i;
 | |
| 
 | |
|     for (i = 0; i < eDOMClassInfoIDCount; i++) {
 | |
|       NS_IF_RELEASE(sClassInfoData[i].mCachedClassInfo);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   sConstructor_id     = JSID_VOID;
 | |
|   sWrappedJSObject_id = JSID_VOID;
 | |
| 
 | |
|   NS_IF_RELEASE(sXPConnect);
 | |
|   sIsInitialized = false;
 | |
| }
 | |
| 
 | |
| static nsresult
 | |
| BaseStubConstructor(nsIWeakReference* aWeakOwner,
 | |
|                     const nsGlobalNameStruct *name_struct, JSContext *cx,
 | |
|                     JS::Handle<JSObject*> obj, const JS::CallArgs &args)
 | |
| {
 | |
|   MOZ_ASSERT(obj);
 | |
|   MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
 | |
| 
 | |
|   nsresult rv;
 | |
|   nsCOMPtr<nsISupports> native;
 | |
|   if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
 | |
|     rv = NS_ERROR_NOT_AVAILABLE;
 | |
|   } else {
 | |
|     MOZ_ASSERT(name_struct->mType ==
 | |
|                nsGlobalNameStruct::eTypeExternalConstructor);
 | |
|     native = do_CreateInstance(name_struct->mCID, &rv);
 | |
|   }
 | |
|   if (NS_FAILED(rv)) {
 | |
|     NS_ERROR("Failed to create the object");
 | |
|     return rv;
 | |
|   }
 | |
| 
 | |
|   js::AssertSameCompartment(cx, obj);
 | |
|   return nsContentUtils::WrapNative(cx, native, args.rval(), true);
 | |
| }
 | |
| 
 | |
| static nsresult
 | |
| DefineInterfaceConstants(JSContext *cx, JS::Handle<JSObject*> obj, const nsIID *aIID)
 | |
| {
 | |
|   nsCOMPtr<nsIInterfaceInfoManager>
 | |
|     iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
 | |
|   NS_ENSURE_TRUE(iim, NS_ERROR_UNEXPECTED);
 | |
| 
 | |
|   nsCOMPtr<nsIInterfaceInfo> if_info;
 | |
| 
 | |
|   nsresult rv = iim->GetInfoForIID(aIID, getter_AddRefs(if_info));
 | |
|   NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && if_info, rv);
 | |
| 
 | |
|   uint16_t constant_count;
 | |
| 
 | |
|   if_info->GetConstantCount(&constant_count);
 | |
| 
 | |
|   if (!constant_count) {
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsIInterfaceInfo> parent_if_info;
 | |
| 
 | |
|   rv = if_info->GetParent(getter_AddRefs(parent_if_info));
 | |
|   NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && parent_if_info, rv);
 | |
| 
 | |
|   uint16_t parent_constant_count, i;
 | |
|   parent_if_info->GetConstantCount(&parent_constant_count);
 | |
| 
 | |
|   JS::Rooted<JS::Value> v(cx);
 | |
|   for (i = parent_constant_count; i < constant_count; i++) {
 | |
|     nsXPIDLCString name;
 | |
|     rv = if_info->GetConstant(i, &v, getter_Copies(name));
 | |
|     NS_ENSURE_TRUE(NS_SUCCEEDED(rv), rv);
 | |
| 
 | |
|     if (!::JS_DefineProperty(cx, obj, name, v,
 | |
|                              JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT,
 | |
|                              JS_STUBGETTER, JS_STUBSETTER)) {
 | |
|       return NS_ERROR_UNEXPECTED;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| class nsDOMConstructor final : public nsIDOMDOMConstructor
 | |
| {
 | |
| protected:
 | |
|   nsDOMConstructor(const char16_t* aName,
 | |
|                    bool aIsConstructable,
 | |
|                    nsPIDOMWindowInner* aOwner)
 | |
|     : mClassName(aName),
 | |
|       mConstructable(aIsConstructable),
 | |
|       mWeakOwner(do_GetWeakReference(aOwner))
 | |
|   {
 | |
|   }
 | |
| 
 | |
|   ~nsDOMConstructor() {}
 | |
| 
 | |
| public:
 | |
| 
 | |
|   static nsresult Create(const char16_t* aName,
 | |
|                          const nsGlobalNameStruct* aNameStruct,
 | |
|                          nsPIDOMWindowInner* aOwner,
 | |
|                          nsDOMConstructor** aResult);
 | |
| 
 | |
|   NS_DECL_ISUPPORTS
 | |
|   NS_DECL_NSIDOMDOMCONSTRUCTOR
 | |
| 
 | |
|   nsresult PreCreate(JSContext *cx, JSObject *globalObj, JSObject **parentObj);
 | |
| 
 | |
|   nsresult Construct(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
 | |
|                      JS::Handle<JSObject*> obj, const JS::CallArgs &args,
 | |
|                      bool *_retval);
 | |
| 
 | |
|   nsresult HasInstance(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
 | |
|                        JS::Handle<JSObject*> obj, const JS::Value &val, bool *bp,
 | |
|                        bool *_retval);
 | |
| 
 | |
|   nsresult ResolveInterfaceConstants(JSContext *cx, JS::Handle<JSObject*> obj);
 | |
| 
 | |
| private:
 | |
|   const nsGlobalNameStruct *GetNameStruct()
 | |
|   {
 | |
|     if (!mClassName) {
 | |
|       NS_ERROR("Can't get name");
 | |
|       return nullptr;
 | |
|     }
 | |
| 
 | |
|     const nsGlobalNameStruct *nameStruct;
 | |
| #ifdef DEBUG
 | |
|     nsresult rv =
 | |
| #endif
 | |
|       GetNameStruct(nsDependentString(mClassName), &nameStruct);
 | |
| 
 | |
|     NS_ASSERTION(NS_FAILED(rv) || nameStruct, "Name isn't in hash.");
 | |
| 
 | |
|     return nameStruct;
 | |
|   }
 | |
| 
 | |
|   static nsresult GetNameStruct(const nsAString& aName,
 | |
|                                 const nsGlobalNameStruct **aNameStruct)
 | |
|   {
 | |
|     *aNameStruct = nullptr;
 | |
| 
 | |
|     nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
 | |
|     if (!nameSpaceManager) {
 | |
|       NS_ERROR("Can't get namespace manager.");
 | |
|       return NS_ERROR_UNEXPECTED;
 | |
|     }
 | |
| 
 | |
|     *aNameStruct = nameSpaceManager->LookupName(aName);
 | |
| 
 | |
|     // Return NS_OK here, aName just isn't a DOM class but nothing failed.
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   static bool IsConstructable(const nsGlobalNameStruct *aNameStruct)
 | |
|   {
 | |
|     return aNameStruct->mType == nsGlobalNameStruct::eTypeExternalConstructor;
 | |
|   }
 | |
| 
 | |
|   const char16_t*   mClassName;
 | |
|   const bool mConstructable;
 | |
|   nsWeakPtr          mWeakOwner;
 | |
| };
 | |
| 
 | |
| //static
 | |
| nsresult
 | |
| nsDOMConstructor::Create(const char16_t* aName,
 | |
|                          const nsGlobalNameStruct* aNameStruct,
 | |
|                          nsPIDOMWindowInner* aOwner,
 | |
|                          nsDOMConstructor** aResult)
 | |
| {
 | |
|   *aResult = nullptr;
 | |
|   // Prevent creating a constructor if aOwner is inner window which doesn't have
 | |
|   // an outer window. If the outer window doesn't have an inner window or the
 | |
|   // caller can't access the outer window's current inner window then try to use
 | |
|   // the owner (so long as it is, in fact, an inner window). If that doesn't
 | |
|   // work then prevent creation also.
 | |
|   nsPIDOMWindowOuter* outerWindow = aOwner->GetOuterWindow();
 | |
|   nsPIDOMWindowInner* currentInner =
 | |
|     outerWindow ? outerWindow->GetCurrentInnerWindow() : aOwner;
 | |
|   if (!currentInner ||
 | |
|       (aOwner != currentInner &&
 | |
|        !nsContentUtils::CanCallerAccess(currentInner) &&
 | |
|        !(currentInner = aOwner)->IsInnerWindow())) {
 | |
|     return NS_ERROR_DOM_SECURITY_ERR;
 | |
|   }
 | |
| 
 | |
|   bool constructable = aNameStruct && IsConstructable(aNameStruct);
 | |
| 
 | |
|   *aResult = new nsDOMConstructor(aName, constructable, currentInner);
 | |
|   NS_ADDREF(*aResult);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMPL_ADDREF(nsDOMConstructor)
 | |
| NS_IMPL_RELEASE(nsDOMConstructor)
 | |
| NS_INTERFACE_MAP_BEGIN(nsDOMConstructor)
 | |
|   NS_INTERFACE_MAP_ENTRY(nsIDOMDOMConstructor)
 | |
|   NS_INTERFACE_MAP_ENTRY(nsISupports)
 | |
|   if (aIID.Equals(NS_GET_IID(nsIClassInfo))) {
 | |
| #ifdef DEBUG
 | |
|     {
 | |
|       const nsGlobalNameStruct *name_struct = GetNameStruct();
 | |
|       NS_ASSERTION(!name_struct ||
 | |
|                    mConstructable == IsConstructable(name_struct),
 | |
|                    "Can't change constructability dynamically!");
 | |
|     }
 | |
| #endif
 | |
|     foundInterface =
 | |
|       NS_GetDOMClassInfoInstance(mConstructable ?
 | |
|                                  eDOMClassInfo_DOMConstructor_id :
 | |
|                                  eDOMClassInfo_DOMPrototype_id);
 | |
|     if (!foundInterface) {
 | |
|       *aInstancePtr = nullptr;
 | |
|       return NS_ERROR_OUT_OF_MEMORY;
 | |
|     }
 | |
|   } else
 | |
| NS_INTERFACE_MAP_END
 | |
| 
 | |
| nsresult
 | |
| nsDOMConstructor::PreCreate(JSContext *cx, JSObject *globalObj, JSObject **parentObj)
 | |
| {
 | |
|   nsCOMPtr<nsPIDOMWindowInner> owner(do_QueryReferent(mWeakOwner));
 | |
|   if (!owner) {
 | |
|     // Can't do anything.
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   nsGlobalWindow *win = nsGlobalWindow::Cast(owner);
 | |
|   return SetParentToWindow(win, parentObj);
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| nsDOMConstructor::Construct(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
 | |
|                             JS::Handle<JSObject*> obj, const JS::CallArgs &args,
 | |
|                             bool *_retval)
 | |
| {
 | |
|   MOZ_ASSERT(obj);
 | |
| 
 | |
|   const nsGlobalNameStruct *name_struct = GetNameStruct();
 | |
|   NS_ENSURE_TRUE(name_struct, NS_ERROR_FAILURE);
 | |
| 
 | |
|   if (!IsConstructable(name_struct)) {
 | |
|     // ignore return value, we return false anyway
 | |
|     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
 | |
|   }
 | |
| 
 | |
|   return BaseStubConstructor(mWeakOwner, name_struct, cx, obj, args);
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| nsDOMConstructor::HasInstance(nsIXPConnectWrappedNative *wrapper,
 | |
|                               JSContext * cx, JS::Handle<JSObject*> obj,
 | |
|                               const JS::Value &v, bool *bp, bool *_retval)
 | |
| 
 | |
| {
 | |
|   // No need to look these up in the hash.
 | |
|   *bp = false;
 | |
|   if (v.isPrimitive()) {
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   JS::Rooted<JSObject*> dom_obj(cx, v.toObjectOrNull());
 | |
|   NS_ASSERTION(dom_obj, "nsDOMConstructor::HasInstance couldn't get object");
 | |
| 
 | |
|   // This might not be the right object, if there are wrappers. Unwrap if we can.
 | |
|   JSObject *wrapped_obj = js::CheckedUnwrap(dom_obj, /* stopAtWindowProxy = */ false);
 | |
|   if (wrapped_obj)
 | |
|       dom_obj = wrapped_obj;
 | |
| 
 | |
|   const JSClass *dom_class = JS_GetClass(dom_obj);
 | |
|   if (!dom_class) {
 | |
|     NS_ERROR("nsDOMConstructor::HasInstance can't get class.");
 | |
|     return NS_ERROR_UNEXPECTED;
 | |
|   }
 | |
| 
 | |
|   const nsGlobalNameStruct *name_struct;
 | |
|   nsresult rv = GetNameStruct(NS_ConvertASCIItoUTF16(dom_class->name), &name_struct);
 | |
|   if (NS_FAILED(rv)) {
 | |
|     return rv;
 | |
|   }
 | |
| 
 | |
|   if (!name_struct) {
 | |
|     // This isn't a normal DOM object, see if this constructor lives on its
 | |
|     // prototype chain.
 | |
|     JS::Rooted<JS::PropertyDescriptor> desc(cx);
 | |
|     if (!JS_GetPropertyDescriptor(cx, obj, "prototype", &desc)) {
 | |
|       return NS_ERROR_UNEXPECTED;
 | |
|     }
 | |
| 
 | |
|     if (!desc.object() || desc.hasGetterOrSetter() || !desc.value().isObject()) {
 | |
|       return NS_OK;
 | |
|     }
 | |
| 
 | |
|     JS::Rooted<JSObject*> dot_prototype(cx, &desc.value().toObject());
 | |
| 
 | |
|     JS::Rooted<JSObject*> proto(cx, dom_obj);
 | |
|     for (;;) {
 | |
|       if (!JS_GetPrototype(cx, proto, &proto)) {
 | |
|         return NS_ERROR_UNEXPECTED;
 | |
|       }
 | |
|       if (!proto) {
 | |
|         break;
 | |
|       }
 | |
|       if (proto == dot_prototype) {
 | |
|         *bp = true;
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   if (name_struct->mType != nsGlobalNameStruct::eTypeClassConstructor) {
 | |
|     // Doesn't have DOM interfaces.
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   const nsGlobalNameStruct *class_name_struct = GetNameStruct();
 | |
|   NS_ENSURE_TRUE(class_name_struct, NS_ERROR_FAILURE);
 | |
| 
 | |
|   if (name_struct == class_name_struct) {
 | |
|     *bp = true;
 | |
| 
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   const nsIID *class_iid;
 | |
|   if (class_name_struct->mType == nsGlobalNameStruct::eTypeClassProto) {
 | |
|     class_iid = &class_name_struct->mIID;
 | |
|   } else if (class_name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
 | |
|     class_iid =
 | |
|       sClassInfoData[class_name_struct->mDOMClassInfoID].mProtoChainInterface;
 | |
|   } else {
 | |
|     *bp = false;
 | |
| 
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   NS_ASSERTION(name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor,
 | |
|                "The constructor was set up with a struct of the wrong type.");
 | |
| 
 | |
|   const nsDOMClassInfoData *ci_data;
 | |
|   if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor &&
 | |
|       name_struct->mDOMClassInfoID >= 0) {
 | |
|     ci_data = &sClassInfoData[name_struct->mDOMClassInfoID];
 | |
|   } else {
 | |
|     ci_data = nullptr;
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsIInterfaceInfoManager>
 | |
|     iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
 | |
|   if (!iim) {
 | |
|     NS_ERROR("nsDOMConstructor::HasInstance can't get interface info mgr.");
 | |
|     return NS_ERROR_UNEXPECTED;
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsIInterfaceInfo> if_info;
 | |
|   uint32_t count = 0;
 | |
|   const nsIID* class_interface;
 | |
|   while ((class_interface = ci_data->mInterfaces[count++])) {
 | |
|     if (class_iid->Equals(*class_interface)) {
 | |
|       *bp = true;
 | |
| 
 | |
|       return NS_OK;
 | |
|     }
 | |
| 
 | |
|     iim->GetInfoForIID(class_interface, getter_AddRefs(if_info));
 | |
|     if (!if_info) {
 | |
|       NS_ERROR("nsDOMConstructor::HasInstance can't get interface info.");
 | |
|       return NS_ERROR_UNEXPECTED;
 | |
|     }
 | |
| 
 | |
|     if_info->HasAncestor(class_iid, bp);
 | |
| 
 | |
|     if (*bp) {
 | |
|       return NS_OK;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| nsDOMConstructor::ResolveInterfaceConstants(JSContext *cx, JS::Handle<JSObject*> obj)
 | |
| {
 | |
|   const nsGlobalNameStruct *class_name_struct = GetNameStruct();
 | |
|   if (!class_name_struct)
 | |
|     return NS_ERROR_UNEXPECTED;
 | |
| 
 | |
|   const nsIID *class_iid;
 | |
|   if (class_name_struct->mType == nsGlobalNameStruct::eTypeClassProto) {
 | |
|     class_iid = &class_name_struct->mIID;
 | |
|   } else if (class_name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
 | |
|     class_iid =
 | |
|       sClassInfoData[class_name_struct->mDOMClassInfoID].mProtoChainInterface;
 | |
|   } else {
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   nsresult rv = DefineInterfaceConstants(cx, obj, class_iid);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMConstructor::ToString(nsAString &aResult)
 | |
| {
 | |
|   aResult.AssignLiteral("[object ");
 | |
|   aResult.Append(mClassName);
 | |
|   aResult.Append(char16_t(']'));
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| static nsresult
 | |
| GetXPCProto(nsIXPConnect *aXPConnect, JSContext *cx, nsGlobalWindow *aWin,
 | |
|             const nsGlobalNameStruct *aNameStruct,
 | |
|             JS::MutableHandle<JSObject*> aProto)
 | |
| {
 | |
|   NS_ASSERTION(aNameStruct->mType == nsGlobalNameStruct::eTypeClassConstructor,
 | |
|                "Wrong type!");
 | |
| 
 | |
|   int32_t id = aNameStruct->mDOMClassInfoID;
 | |
|   MOZ_ASSERT(id >= 0, "Negative DOM classinfo?!?");
 | |
| 
 | |
|   nsDOMClassInfoID ci_id = (nsDOMClassInfoID)id;
 | |
| 
 | |
|   nsCOMPtr<nsIClassInfo> ci = NS_GetDOMClassInfoInstance(ci_id);
 | |
|   NS_ENSURE_TRUE(ci, NS_ERROR_UNEXPECTED);
 | |
| 
 | |
|   nsresult rv =
 | |
|     aXPConnect->GetWrappedNativePrototype(cx, aWin->GetGlobalJSObject(), ci, aProto.address());
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   return JS_WrapObject(cx, aProto) ? NS_OK : NS_ERROR_FAILURE;
 | |
| }
 | |
| 
 | |
| // Either ci_data must be non-null or name_struct must be non-null and of type
 | |
| // eTypeClassProto.
 | |
| static nsresult
 | |
| ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx,
 | |
|                  JS::Handle<JSObject*> obj, const char16_t *name,
 | |
|                  const nsDOMClassInfoData *ci_data,
 | |
|                  const nsGlobalNameStruct *name_struct,
 | |
|                  nsScriptNameSpaceManager *nameSpaceManager,
 | |
|                  JSObject* aDot_prototype,
 | |
|                  JS::MutableHandle<JS::PropertyDescriptor> ctorDesc)
 | |
| {
 | |
|   JS::Rooted<JSObject*> dot_prototype(cx, aDot_prototype);
 | |
|   NS_ASSERTION(ci_data ||
 | |
|                (name_struct &&
 | |
|                 name_struct->mType == nsGlobalNameStruct::eTypeClassProto),
 | |
|                "Wrong type or missing ci_data!");
 | |
| 
 | |
|   RefPtr<nsDOMConstructor> constructor;
 | |
|   nsresult rv = nsDOMConstructor::Create(name, name_struct, aWin->AsInner(),
 | |
|                                          getter_AddRefs(constructor));
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   JS::Rooted<JS::Value> v(cx);
 | |
| 
 | |
|   js::AssertSameCompartment(cx, obj);
 | |
|   rv = nsContentUtils::WrapNative(cx, constructor,
 | |
|                                   &NS_GET_IID(nsIDOMDOMConstructor), &v,
 | |
|                                   false);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   FillPropertyDescriptor(ctorDesc, obj, 0, v);
 | |
|   // And make sure we wrap the value into the right compartment.  Note that we
 | |
|   // do this with ctorDesc.value(), not with v, because we need v to be in the
 | |
|   // right compartment (that of the reflector of |constructor|) below.
 | |
|   if (!JS_WrapValue(cx, ctorDesc.value())) {
 | |
|     return NS_ERROR_UNEXPECTED;
 | |
|   }
 | |
| 
 | |
|   JS::Rooted<JSObject*> class_obj(cx, &v.toObject());
 | |
| 
 | |
|   const nsIID *primary_iid = &NS_GET_IID(nsISupports);
 | |
| 
 | |
|   if (!ci_data) {
 | |
|     primary_iid = &name_struct->mIID;
 | |
|   }
 | |
|   else if (ci_data->mProtoChainInterface) {
 | |
|     primary_iid = ci_data->mProtoChainInterface;
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsIInterfaceInfo> if_info;
 | |
|   nsCOMPtr<nsIInterfaceInfo> parent;
 | |
|   const char *class_parent_name = nullptr;
 | |
| 
 | |
|   if (!primary_iid->Equals(NS_GET_IID(nsISupports))) {
 | |
|     JSAutoCompartment ac(cx, class_obj);
 | |
| 
 | |
|     rv = DefineInterfaceConstants(cx, class_obj, primary_iid);
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|     nsCOMPtr<nsIInterfaceInfoManager>
 | |
|       iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
 | |
|     NS_ENSURE_TRUE(iim, NS_ERROR_NOT_AVAILABLE);
 | |
| 
 | |
|     iim->GetInfoForIID(primary_iid, getter_AddRefs(if_info));
 | |
|     NS_ENSURE_TRUE(if_info, NS_ERROR_UNEXPECTED);
 | |
| 
 | |
|     const nsIID *iid = nullptr;
 | |
| 
 | |
|     if (ci_data && !ci_data->mHasClassInterface) {
 | |
|       if_info->GetIIDShared(&iid);
 | |
|     } else {
 | |
|       if_info->GetParent(getter_AddRefs(parent));
 | |
|       NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED);
 | |
| 
 | |
|       parent->GetIIDShared(&iid);
 | |
|     }
 | |
| 
 | |
|     if (iid) {
 | |
|       if (!iid->Equals(NS_GET_IID(nsISupports))) {
 | |
|         if (ci_data && !ci_data->mHasClassInterface) {
 | |
|           // If the class doesn't have a class interface the primary
 | |
|           // interface is the interface that should be
 | |
|           // constructor.prototype.__proto__.
 | |
| 
 | |
|           if_info->GetNameShared(&class_parent_name);
 | |
|         } else {
 | |
|           // If the class does have a class interface (or there's no
 | |
|           // real class for this name) then the parent of the
 | |
|           // primary interface is what we want on
 | |
|           // constructor.prototype.__proto__.
 | |
| 
 | |
|           NS_ASSERTION(parent, "Whoa, this is bad, null parent here!");
 | |
| 
 | |
|           parent->GetNameShared(&class_parent_name);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   {
 | |
|     JS::Rooted<JSObject*> winobj(cx, aWin->FastGetGlobalJSObject());
 | |
| 
 | |
|     JS::Rooted<JSObject*> proto(cx);
 | |
| 
 | |
|     if (class_parent_name) {
 | |
|       JSAutoCompartment ac(cx, winobj);
 | |
| 
 | |
|       JS::Rooted<JS::PropertyDescriptor> desc(cx);
 | |
|       if (!JS_GetPropertyDescriptor(cx, winobj, CutPrefix(class_parent_name), &desc)) {
 | |
|         return NS_ERROR_UNEXPECTED;
 | |
|       }
 | |
| 
 | |
|       if (desc.object() && !desc.hasGetterOrSetter() && desc.value().isObject()) {
 | |
|         JS::Rooted<JSObject*> obj(cx, &desc.value().toObject());
 | |
|         if (!JS_GetPropertyDescriptor(cx, obj, "prototype", &desc)) {
 | |
|           return NS_ERROR_UNEXPECTED;
 | |
|         }
 | |
| 
 | |
|         if (desc.object() && !desc.hasGetterOrSetter() && desc.value().isObject()) {
 | |
|           proto = &desc.value().toObject();
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (dot_prototype) {
 | |
|       JSAutoCompartment ac(cx, dot_prototype);
 | |
|       JS::Rooted<JSObject*> xpc_proto_proto(cx);
 | |
|       if (!::JS_GetPrototype(cx, dot_prototype, &xpc_proto_proto)) {
 | |
|         return NS_ERROR_UNEXPECTED;
 | |
|       }
 | |
| 
 | |
|       if (proto &&
 | |
|           (!xpc_proto_proto ||
 | |
|            JS_GetClass(xpc_proto_proto) == sObjectClass)) {
 | |
|         if (!JS_WrapObject(cx, &proto) ||
 | |
|             !JS_SetPrototype(cx, dot_prototype, proto)) {
 | |
|           return NS_ERROR_UNEXPECTED;
 | |
|         }
 | |
|       }
 | |
|     } else {
 | |
|       JSAutoCompartment ac(cx, winobj);
 | |
|       if (!proto) {
 | |
|         proto = JS_GetObjectPrototype(cx, winobj);
 | |
|       }
 | |
|       dot_prototype = ::JS_NewObjectWithUniqueType(cx,
 | |
|                                                    &sDOMConstructorProtoClass,
 | |
|                                                    proto);
 | |
|       NS_ENSURE_TRUE(dot_prototype, NS_ERROR_OUT_OF_MEMORY);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   v.setObject(*dot_prototype);
 | |
| 
 | |
|   JSAutoCompartment ac(cx, class_obj);
 | |
| 
 | |
|   // Per ECMA, the prototype property is {DontEnum, DontDelete, ReadOnly}
 | |
|   if (!JS_WrapValue(cx, &v) ||
 | |
|       !JS_DefineProperty(cx, class_obj, "prototype", v,
 | |
|                          JSPROP_PERMANENT | JSPROP_READONLY,
 | |
|                          JS_STUBGETTER, JS_STUBSETTER)) {
 | |
|     return NS_ERROR_UNEXPECTED;
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| static bool
 | |
| OldBindingConstructorEnabled(const nsGlobalNameStruct *aStruct,
 | |
|                              nsGlobalWindow *aWin, JSContext *cx)
 | |
| {
 | |
|   MOZ_ASSERT(aStruct->mType == nsGlobalNameStruct::eTypeProperty ||
 | |
|              aStruct->mType == nsGlobalNameStruct::eTypeClassConstructor);
 | |
| 
 | |
|   // Don't expose chrome only constructors to content windows.
 | |
|   if (aStruct->mChromeOnly) {
 | |
|     bool expose;
 | |
|     if (aStruct->mAllowXBL) {
 | |
|       expose = IsChromeOrXBL(cx, nullptr);
 | |
|     } else {
 | |
|       expose = nsContentUtils::IsSystemPrincipal(aWin->GetPrincipal());
 | |
|     }
 | |
| 
 | |
|     if (!expose) {
 | |
|       return false;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| static nsresult
 | |
| LookupComponentsShim(JSContext *cx, JS::Handle<JSObject*> global,
 | |
|                      nsPIDOMWindowInner *win,
 | |
|                      JS::MutableHandle<JS::PropertyDescriptor> desc);
 | |
| 
 | |
| // static
 | |
| bool
 | |
| nsWindowSH::NameStructEnabled(JSContext* aCx, nsGlobalWindow *aWin,
 | |
|                               const nsAString& aName,
 | |
|                               const nsGlobalNameStruct& aNameStruct)
 | |
| {
 | |
|   const nsGlobalNameStruct* nameStruct = &aNameStruct;
 | |
|   return (nameStruct->mType != nsGlobalNameStruct::eTypeProperty &&
 | |
|           nameStruct->mType != nsGlobalNameStruct::eTypeClassConstructor) ||
 | |
|          OldBindingConstructorEnabled(nameStruct, aWin, aCx);
 | |
| }
 | |
| 
 | |
| #ifdef RELEASE_BUILD
 | |
| #define USE_CONTROLLERS_SHIM
 | |
| #endif
 | |
| 
 | |
| #ifdef USE_CONTROLLERS_SHIM
 | |
| static const JSClass ControllersShimClass = {
 | |
|     "XULControllers", 0
 | |
| };
 | |
| #endif
 | |
| 
 | |
| // static
 | |
| nsresult
 | |
| nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
 | |
|                           JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
 | |
|                           JS::MutableHandle<JS::PropertyDescriptor> desc)
 | |
| {
 | |
|   if (id == XPCJSRuntime::Get()->GetStringID(XPCJSRuntime::IDX_COMPONENTS)) {
 | |
|     return LookupComponentsShim(cx, obj, aWin->AsInner(), desc);
 | |
|   }
 | |
| 
 | |
| #ifdef USE_CONTROLLERS_SHIM
 | |
|   // Note: We use |obj| rather than |aWin| to get the principal here, because
 | |
|   // this is called during Window setup when the Document isn't necessarily
 | |
|   // hooked up yet.
 | |
|   if (id == XPCJSRuntime::Get()->GetStringID(XPCJSRuntime::IDX_CONTROLLERS) &&
 | |
|       !xpc::IsXrayWrapper(obj) &&
 | |
|       !nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(obj)))
 | |
|   {
 | |
|     if (aWin->GetDoc()) {
 | |
|       aWin->GetDoc()->WarnOnceAbout(nsIDocument::eWindow_Controllers);
 | |
|     }
 | |
|     MOZ_ASSERT(JS_IsGlobalObject(obj));
 | |
|     JS::Rooted<JSObject*> shim(cx, JS_NewObject(cx, &ControllersShimClass));
 | |
|     if (NS_WARN_IF(!shim)) {
 | |
|       return NS_ERROR_OUT_OF_MEMORY;
 | |
|     }
 | |
|     FillPropertyDescriptor(desc, obj, JS::ObjectValue(*shim), /* readOnly = */ false);
 | |
|     return NS_OK;
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
 | |
|   NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
 | |
| 
 | |
|   // Note - Our only caller is nsGlobalWindow::DoResolve, which checks that
 | |
|   // JSID_IS_STRING(id) is true.
 | |
|   nsAutoJSString name;
 | |
|   if (!name.init(cx, JSID_TO_STRING(id))) {
 | |
|     return NS_ERROR_OUT_OF_MEMORY;
 | |
|   }
 | |
| 
 | |
|   const char16_t *class_name = nullptr;
 | |
|   const nsGlobalNameStruct *name_struct =
 | |
|     nameSpaceManager->LookupName(name, &class_name);
 | |
| 
 | |
|   if (!name_struct) {
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   // The class_name had better match our name
 | |
|   MOZ_ASSERT(name.Equals(class_name));
 | |
| 
 | |
|   NS_ENSURE_TRUE(class_name, NS_ERROR_UNEXPECTED);
 | |
| 
 | |
|   nsresult rv = NS_OK;
 | |
| 
 | |
|   if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
 | |
|     if (!OldBindingConstructorEnabled(name_struct, aWin, cx)) {
 | |
|       return NS_OK;
 | |
|     }
 | |
| 
 | |
|     // Create the XPConnect prototype for our classinfo, PostCreateProto will
 | |
|     // set up the prototype chain.  This will go ahead and define things on the
 | |
|     // actual window's global.
 | |
|     JS::Rooted<JSObject*> dot_prototype(cx);
 | |
|     rv = GetXPCProto(nsDOMClassInfo::sXPConnect, cx, aWin, name_struct,
 | |
|                      &dot_prototype);
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
|     MOZ_ASSERT(dot_prototype);
 | |
| 
 | |
|     bool isXray = xpc::WrapperFactory::IsXrayWrapper(obj);
 | |
|     MOZ_ASSERT_IF(obj != aWin->GetGlobalJSObject(), isXray);
 | |
|     if (!isXray) {
 | |
|       // GetXPCProto already defined the property for us
 | |
|       FillPropertyDescriptor(desc, obj, JS::UndefinedValue(), false);
 | |
|       return NS_OK;
 | |
|     }
 | |
| 
 | |
|     // This is the Xray case.  Look up the constructor object for this
 | |
|     // prototype.
 | |
|     return ResolvePrototype(nsDOMClassInfo::sXPConnect, aWin, cx, obj,
 | |
|                             class_name,
 | |
|                             &sClassInfoData[name_struct->mDOMClassInfoID],
 | |
|                             name_struct, nameSpaceManager, dot_prototype,
 | |
|                             desc);
 | |
|   }
 | |
| 
 | |
|   if (name_struct->mType == nsGlobalNameStruct::eTypeClassProto) {
 | |
|     // We don't have a XPConnect prototype object, let ResolvePrototype create
 | |
|     // one.
 | |
|     return ResolvePrototype(nsDOMClassInfo::sXPConnect, aWin, cx, obj,
 | |
|                             class_name, nullptr,
 | |
|                             name_struct, nameSpaceManager, nullptr, desc);
 | |
|   }
 | |
| 
 | |
|   if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructor) {
 | |
|     RefPtr<nsDOMConstructor> constructor;
 | |
|     rv = nsDOMConstructor::Create(class_name, name_struct, aWin->AsInner(),
 | |
|                                   getter_AddRefs(constructor));
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|     JS::Rooted<JS::Value> val(cx);
 | |
|     js::AssertSameCompartment(cx, obj);
 | |
|     rv = nsContentUtils::WrapNative(cx, constructor,
 | |
|                                     &NS_GET_IID(nsIDOMDOMConstructor), &val,
 | |
|                                     true);
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|     NS_ASSERTION(val.isObject(), "Why didn't we get a JSObject?");
 | |
| 
 | |
|     FillPropertyDescriptor(desc, obj, 0, val);
 | |
| 
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   if (name_struct->mType == nsGlobalNameStruct::eTypeProperty) {
 | |
|     if (!OldBindingConstructorEnabled(name_struct, aWin, cx))
 | |
|       return NS_OK;
 | |
| 
 | |
|     // Before defining a global property, check for a named subframe of the
 | |
|     // same name. If it exists, we don't want to shadow it.
 | |
|     if (nsCOMPtr<nsPIDOMWindowOuter> childWin = aWin->GetChildWindow(name)) {
 | |
|       return NS_OK;
 | |
|     }
 | |
| 
 | |
|     nsCOMPtr<nsISupports> native(do_CreateInstance(name_struct->mCID, &rv));
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|     JS::Rooted<JS::Value> prop_val(cx, JS::UndefinedValue()); // Property value.
 | |
| 
 | |
|     nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi(do_QueryInterface(native));
 | |
|     if (gpi) {
 | |
|       rv = gpi->Init(aWin->AsInner(), &prop_val);
 | |
|       NS_ENSURE_SUCCESS(rv, rv);
 | |
|     }
 | |
| 
 | |
|     if (prop_val.isPrimitive() && !prop_val.isNull()) {
 | |
|       rv = nsContentUtils::WrapNative(cx, native, &prop_val, true);
 | |
|     }
 | |
| 
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|     if (!JS_WrapValue(cx, &prop_val)) {
 | |
|       return NS_ERROR_UNEXPECTED;
 | |
|     }
 | |
| 
 | |
|     FillPropertyDescriptor(desc, obj, prop_val, false);
 | |
| 
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| struct InterfaceShimEntry {
 | |
|   const char *geckoName;
 | |
|   const char *domName;
 | |
| };
 | |
| 
 | |
| // We add shims from Components.interfaces.nsIDOMFoo to window.Foo for each
 | |
| // interface that has interface constants that sites might be getting off
 | |
| // of Ci.
 | |
| const InterfaceShimEntry kInterfaceShimMap[] =
 | |
| { { "nsIXMLHttpRequest", "XMLHttpRequest" },
 | |
|   { "nsIDOMDOMException", "DOMException" },
 | |
|   { "nsIDOMNode", "Node" },
 | |
|   { "nsIDOMCSSPrimitiveValue", "CSSPrimitiveValue" },
 | |
|   { "nsIDOMCSSRule", "CSSRule" },
 | |
|   { "nsIDOMCSSValue", "CSSValue" },
 | |
|   { "nsIDOMEvent", "Event" },
 | |
|   { "nsIDOMNSEvent", "Event" },
 | |
|   { "nsIDOMKeyEvent", "KeyEvent" },
 | |
|   { "nsIDOMMouseEvent", "MouseEvent" },
 | |
|   { "nsIDOMMouseScrollEvent", "MouseScrollEvent" },
 | |
|   { "nsIDOMMutationEvent", "MutationEvent" },
 | |
|   { "nsIDOMSimpleGestureEvent", "SimpleGestureEvent" },
 | |
|   { "nsIDOMUIEvent", "UIEvent" },
 | |
|   { "nsIDOMHTMLMediaElement", "HTMLMediaElement" },
 | |
|   { "nsIDOMMediaError", "MediaError" },
 | |
|   { "nsIDOMOfflineResourceList", "OfflineResourceList" },
 | |
|   { "nsIDOMRange", "Range" },
 | |
|   { "nsIDOMSVGLength", "SVGLength" },
 | |
|   { "nsIDOMNodeFilter", "NodeFilter" },
 | |
|   { "nsIDOMXPathResult", "XPathResult" } };
 | |
| 
 | |
| static nsresult
 | |
| LookupComponentsShim(JSContext *cx, JS::Handle<JSObject*> global,
 | |
|                      nsPIDOMWindowInner *win,
 | |
|                      JS::MutableHandle<JS::PropertyDescriptor> desc)
 | |
| {
 | |
|   // Keep track of how often this happens.
 | |
|   Telemetry::Accumulate(Telemetry::COMPONENTS_SHIM_ACCESSED_BY_CONTENT, true);
 | |
| 
 | |
|   // Warn once.
 | |
|   nsCOMPtr<nsIDocument> doc = win->GetExtantDoc();
 | |
|   if (doc) {
 | |
|     doc->WarnOnceAbout(nsIDocument::eComponents, /* asError = */ true);
 | |
|   }
 | |
| 
 | |
|   // Create a fake Components object.
 | |
|   AssertSameCompartment(cx, global);
 | |
|   JS::Rooted<JSObject*> components(cx, JS_NewPlainObject(cx));
 | |
|   NS_ENSURE_TRUE(components, NS_ERROR_OUT_OF_MEMORY);
 | |
| 
 | |
|   // Create a fake interfaces object.
 | |
|   JS::Rooted<JSObject*> interfaces(cx, JS_NewPlainObject(cx));
 | |
|   NS_ENSURE_TRUE(interfaces, NS_ERROR_OUT_OF_MEMORY);
 | |
|   bool ok =
 | |
|     JS_DefineProperty(cx, components, "interfaces", interfaces,
 | |
|                       JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY,
 | |
|                       JS_STUBGETTER, JS_STUBSETTER);
 | |
|   NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
 | |
| 
 | |
|   // Define a bunch of shims from the Ci.nsIDOMFoo to window.Foo for DOM
 | |
|   // interfaces with constants.
 | |
|   for (uint32_t i = 0; i < ArrayLength(kInterfaceShimMap); ++i) {
 | |
| 
 | |
|     // Grab the names from the table.
 | |
|     const char *geckoName = kInterfaceShimMap[i].geckoName;
 | |
|     const char *domName = kInterfaceShimMap[i].domName;
 | |
| 
 | |
|     // Look up the appopriate interface object on the global.
 | |
|     JS::Rooted<JS::Value> v(cx, JS::UndefinedValue());
 | |
|     ok = JS_GetProperty(cx, global, domName, &v);
 | |
|     NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
 | |
|     if (!v.isObject()) {
 | |
|       NS_WARNING("Unable to find interface object on global");
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     // Define the shim on the interfaces object.
 | |
|     ok = JS_DefineProperty(cx, interfaces, geckoName, v,
 | |
|                            JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY,
 | |
|                            JS_STUBGETTER, JS_STUBSETTER);
 | |
|     NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
 | |
|   }
 | |
| 
 | |
|   FillPropertyDescriptor(desc, global, JS::ObjectValue(*components), false);
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| // EventTarget helper
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsEventTargetSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
 | |
|                            JSObject *aGlobalObj, JSObject **parentObj)
 | |
| {
 | |
|   JS::Rooted<JSObject*> globalObj(cx, aGlobalObj);
 | |
|   DOMEventTargetHelper* target = DOMEventTargetHelper::FromSupports(nativeObj);
 | |
| 
 | |
|   nsCOMPtr<nsIScriptGlobalObject> native_parent;
 | |
|   target->GetParentObject(getter_AddRefs(native_parent));
 | |
| 
 | |
|   *parentObj = native_parent ? native_parent->GetGlobalJSObject() : globalObj;
 | |
| 
 | |
|   return *parentObj ? NS_OK : NS_ERROR_FAILURE;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsEventTargetSH::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
 | |
|                              JSObject *obj, jsid id, JS::Handle<JS::Value> val,
 | |
|                              bool *_retval)
 | |
| {
 | |
|   nsEventTargetSH::PreserveWrapper(GetNative(wrapper, obj));
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| void
 | |
| nsEventTargetSH::PreserveWrapper(nsISupports *aNative)
 | |
| {
 | |
|   DOMEventTargetHelper* target = DOMEventTargetHelper::FromSupports(aNative);
 | |
|   target->PreserveWrapper(aNative);
 | |
| }
 | |
| 
 | |
| // nsIDOMEventListener::HandleEvent() 'this' converter helper
 | |
| 
 | |
| NS_INTERFACE_MAP_BEGIN(nsEventListenerThisTranslator)
 | |
|   NS_INTERFACE_MAP_ENTRY(nsIXPCFunctionThisTranslator)
 | |
|   NS_INTERFACE_MAP_ENTRY(nsISupports)
 | |
| NS_INTERFACE_MAP_END
 | |
| 
 | |
| 
 | |
| NS_IMPL_ADDREF(nsEventListenerThisTranslator)
 | |
| NS_IMPL_RELEASE(nsEventListenerThisTranslator)
 | |
| 
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsEventListenerThisTranslator::TranslateThis(nsISupports *aInitialThis,
 | |
|                                              nsISupports **_retval)
 | |
| {
 | |
|   nsCOMPtr<nsIDOMEvent> event(do_QueryInterface(aInitialThis));
 | |
|   NS_ENSURE_TRUE(event, NS_ERROR_UNEXPECTED);
 | |
| 
 | |
|   nsCOMPtr<EventTarget> target = event->InternalDOMEvent()->GetCurrentTarget();
 | |
|   target.forget(_retval);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMConstructorSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
 | |
|                               JSObject *aGlobalObj, JSObject **parentObj)
 | |
| {
 | |
|   JS::Rooted<JSObject*> globalObj(cx, aGlobalObj);
 | |
|   nsDOMConstructor *wrapped = static_cast<nsDOMConstructor *>(nativeObj);
 | |
| 
 | |
| #ifdef DEBUG
 | |
|   {
 | |
|     nsCOMPtr<nsIDOMDOMConstructor> is_constructor =
 | |
|       do_QueryInterface(nativeObj);
 | |
|     NS_ASSERTION(is_constructor, "How did we not get a constructor?");
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   return wrapped->PreCreate(cx, globalObj, parentObj);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMConstructorSH::Resolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
 | |
|                             JSObject *aObj, jsid aId, bool *resolvedp,
 | |
|                             bool *_retval)
 | |
| {
 | |
|   JS::Rooted<JSObject*> obj(cx, aObj);
 | |
|   JS::Rooted<jsid> id(cx, aId);
 | |
|   // For regular DOM constructors, we have our interface constants defined on
 | |
|   // us by nsWindowSH::GlobalResolve. However, XrayWrappers can't see these
 | |
|   // interface constants (as they look like expando properties) so we have to
 | |
|   // specially resolve those constants here, but only for Xray wrappers.
 | |
|   if (!ObjectIsNativeWrapper(cx, obj)) {
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   JS::Rooted<JSObject*> nativePropsObj(cx, xpc::XrayUtils::GetNativePropertiesObject(cx, obj));
 | |
|   nsDOMConstructor *wrapped =
 | |
|     static_cast<nsDOMConstructor *>(wrapper->Native());
 | |
|   nsresult rv = wrapped->ResolveInterfaceConstants(cx, nativePropsObj);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   // Now re-lookup the ID to see if we should report back that we resolved the
 | |
|   // looked-for constant. Note that we don't have to worry about infinitely
 | |
|   // recurring back here because the Xray wrapper's holder object doesn't call
 | |
|   // Resolve hooks.
 | |
|   bool found;
 | |
|   if (!JS_HasPropertyById(cx, nativePropsObj, id, &found)) {
 | |
|     *_retval = false;
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   if (found) {
 | |
|     *resolvedp = true;
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMConstructorSH::Call(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
 | |
|                          JSObject *aObj, const JS::CallArgs &args, bool *_retval)
 | |
| {
 | |
|   JS::Rooted<JSObject*> obj(cx, aObj);
 | |
|   MOZ_ASSERT(obj);
 | |
| 
 | |
|   nsDOMConstructor *wrapped =
 | |
|     static_cast<nsDOMConstructor *>(wrapper->Native());
 | |
| 
 | |
| #ifdef DEBUG
 | |
|   {
 | |
|     nsCOMPtr<nsIDOMDOMConstructor> is_constructor =
 | |
|       do_QueryWrappedNative(wrapper);
 | |
|     NS_ASSERTION(is_constructor, "How did we not get a constructor?");
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   return wrapped->Construct(wrapper, cx, obj, args, _retval);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMConstructorSH::Construct(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
 | |
|                               JSObject *aObj, const JS::CallArgs &args, bool *_retval)
 | |
| {
 | |
|   JS::Rooted<JSObject*> obj(cx, aObj);
 | |
|   MOZ_ASSERT(obj);
 | |
| 
 | |
|   nsDOMConstructor *wrapped =
 | |
|     static_cast<nsDOMConstructor *>(wrapper->Native());
 | |
| 
 | |
| #ifdef DEBUG
 | |
|   {
 | |
|     nsCOMPtr<nsIDOMDOMConstructor> is_constructor =
 | |
|       do_QueryWrappedNative(wrapper);
 | |
|     NS_ASSERTION(is_constructor, "How did we not get a constructor?");
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   return wrapped->Construct(wrapper, cx, obj, args, _retval);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDOMConstructorSH::HasInstance(nsIXPConnectWrappedNative *wrapper,
 | |
|                                 JSContext *cx, JSObject *aObj, JS::Handle<JS::Value> val,
 | |
|                                 bool *bp, bool *_retval)
 | |
| {
 | |
|   JS::Rooted<JSObject*> obj(cx, aObj);
 | |
|   nsDOMConstructor *wrapped =
 | |
|     static_cast<nsDOMConstructor *>(wrapper->Native());
 | |
| 
 | |
| #ifdef DEBUG
 | |
|   {
 | |
|     nsCOMPtr<nsIDOMDOMConstructor> is_constructor =
 | |
|       do_QueryWrappedNative(wrapper);
 | |
|     NS_ASSERTION(is_constructor, "How did we not get a constructor?");
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   return wrapped->HasInstance(wrapper, cx, obj, val, bp, _retval);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsNonDOMObjectSH::GetFlags(uint32_t *aFlags)
 | |
| {
 | |
|   // This is NOT a DOM Object.  Use this helper class for cases when you need
 | |
|   // to do something like implement nsISecurityCheckedComponent in a meaningful
 | |
|   // way.
 | |
|   *aFlags = nsIClassInfo::MAIN_THREAD_ONLY | nsIClassInfo::SINGLETON_CLASSINFO;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| // nsContentFrameMessageManagerSH
 | |
| 
 | |
| template<typename Super>
 | |
| NS_IMETHODIMP
 | |
| nsMessageManagerSH<Super>::Resolve(nsIXPConnectWrappedNative* wrapper,
 | |
|                                    JSContext* cx, JSObject* obj_,
 | |
|                                    jsid id_, bool* resolvedp,
 | |
|                                    bool* _retval)
 | |
| {
 | |
|   JS::Rooted<JSObject*> obj(cx, obj_);
 | |
|   JS::Rooted<jsid> id(cx, id_);
 | |
| 
 | |
|   *_retval = SystemGlobalResolve(cx, obj, id, resolvedp);
 | |
|   NS_ENSURE_TRUE(*_retval, NS_ERROR_FAILURE);
 | |
| 
 | |
|   if (*resolvedp) {
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   return Super::Resolve(wrapper, cx, obj, id, resolvedp, _retval);
 | |
| }
 | |
| 
 | |
| template<typename Super>
 | |
| NS_IMETHODIMP
 | |
| nsMessageManagerSH<Super>::Enumerate(nsIXPConnectWrappedNative* wrapper,
 | |
|                                      JSContext* cx, JSObject* obj_,
 | |
|                                      bool* _retval)
 | |
| {
 | |
|   JS::Rooted<JSObject*> obj(cx, obj_);
 | |
| 
 | |
|   *_retval = SystemGlobalEnumerate(cx, obj);
 | |
|   NS_ENSURE_TRUE(*_retval, NS_ERROR_FAILURE);
 | |
| 
 | |
|   // Don't call up to our superclass, since neither nsDOMGenericSH nor
 | |
|   // nsEventTargetSH have WANT_ENUMERATE.
 | |
|   return NS_OK;
 | |
| }
 | 
