Bumping gaia.json for 2 gaia revision(s) a=gaia-bump
[gecko.git] / dom / base / nsDOMClassInfo.cpp
blob89d950ca0f096d8797f44665455390ca0fef5931
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=78: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/ArrayUtils.h"
9 #ifdef XP_WIN
10 #undef GetClassName
11 #endif
13 // JavaScript includes
14 #include "jsapi.h"
15 #include "jsfriendapi.h"
16 #include "WrapperFactory.h"
17 #include "AccessCheck.h"
18 #include "XrayWrapper.h"
20 #include "xpcpublic.h"
21 #include "xpcprivate.h"
22 #include "XPCWrapper.h"
24 #include "mozilla/DOMEventTargetHelper.h"
25 #include "mozilla/dom/RegisterBindings.h"
27 #include "nscore.h"
28 #include "nsDOMClassInfo.h"
29 #include "nsCRT.h"
30 #include "nsCRTGlue.h"
31 #include "nsICategoryManager.h"
32 #include "nsIComponentRegistrar.h"
33 #include "nsXPCOM.h"
34 #include "nsISupportsPrimitives.h"
35 #include "nsIXPConnect.h"
36 #include "xptcall.h"
37 #include "nsTArray.h"
38 #include "nsDocument.h" // nsDOMStyleSheetList
39 #include "nsDOMBlobBuilder.h"
41 // General helper includes
42 #include "nsGlobalWindow.h"
43 #include "nsIContent.h"
44 #include "nsIDocument.h"
45 #include "nsIDOMDocument.h"
46 #include "nsIDOMEvent.h"
47 #include "nsIDOMEventListener.h"
48 #include "nsContentUtils.h"
49 #include "nsIDOMGlobalPropertyInitializer.h"
50 #include "mozilla/Attributes.h"
51 #include "mozilla/Telemetry.h"
53 // Window scriptable helper includes
54 #include "nsIDocShell.h"
55 #include "nsJSUtils.h"
56 #include "nsScriptNameSpaceManager.h"
57 #include "nsIJSNativeInitializer.h"
58 #include "nsJSEnvironment.h"
60 // DOM base includes
61 #include "nsIDOMLocation.h"
62 #include "nsIDOMWindow.h"
63 #include "nsPIDOMWindow.h"
64 #include "nsIDOMJSWindow.h"
65 #include "nsIDOMChromeWindow.h"
66 #include "nsIDOMConstructor.h"
68 // DOM core includes
69 #include "nsError.h"
70 #include "nsIDOMUserDataHandler.h"
71 #include "nsIDOMXULButtonElement.h"
72 #include "nsIDOMXULCheckboxElement.h"
73 #include "nsIDOMXULPopupElement.h"
75 // Event related includes
76 #include "nsIDOMEventTarget.h"
78 // CSS related includes
79 #include "nsCSSRules.h"
80 #include "nsIDOMCSSRule.h"
81 #include "nsAutoPtr.h"
82 #include "nsMemory.h"
84 // Tranformiix
85 #include "nsIXSLTProcessor.h"
86 #include "nsIXSLTProcessorPrivate.h"
88 // includes needed for the prototype chain interfaces
89 #include "nsIDOMCSSCharsetRule.h"
90 #include "nsIDOMCSSImportRule.h"
91 #include "nsIDOMCSSMediaRule.h"
92 #include "nsIDOMCSSFontFaceRule.h"
93 #include "nsIDOMCSSMozDocumentRule.h"
94 #include "nsIDOMCSSSupportsRule.h"
95 #include "nsIDOMMozCSSKeyframeRule.h"
96 #include "nsIDOMMozCSSKeyframesRule.h"
97 #include "nsIDOMCSSCounterStyleRule.h"
98 #include "nsIDOMCSSPageRule.h"
99 #include "nsIDOMCSSStyleRule.h"
100 #include "nsIDOMXULCommandDispatcher.h"
101 #include "nsIControllers.h"
102 #include "nsIBoxObject.h"
103 #ifdef MOZ_XUL
104 #include "nsITreeSelection.h"
105 #include "nsITreeContentView.h"
106 #include "nsITreeView.h"
107 #include "nsIXULTemplateBuilder.h"
108 #include "nsITreeColumns.h"
109 #endif
110 #include "nsIDOMXPathNSResolver.h"
112 // Drag and drop
113 #include "nsIDOMFile.h"
114 #include "nsDOMBlobBuilder.h" // nsDOMMultipartFile
116 #include "nsIEventListenerService.h"
117 #include "nsIMessageManager.h"
119 #include "mozilla/dom/TouchEvent.h"
121 #include "nsWrapperCacheInlines.h"
122 #include "mozilla/dom/HTMLCollectionBinding.h"
124 #include "nsIDOMMozSmsMessage.h"
125 #include "nsIDOMMozMmsMessage.h"
126 #include "nsIDOMMozMobileMessageThread.h"
128 #ifdef MOZ_B2G_FM
129 #include "FMRadio.h"
130 #endif
132 #include "nsIDOMGlobalObjectConstructor.h"
133 #include "nsDebug.h"
135 #include "mozilla/dom/BindingUtils.h"
136 #include "mozilla/Likely.h"
137 #include "WindowNamedPropertiesHandler.h"
138 #include "nsIInterfaceInfoManager.h"
139 #include "mozilla/dom/EventTargetBinding.h"
140 #include "mozilla/dom/WindowBinding.h"
142 #ifdef MOZ_TIME_MANAGER
143 #include "TimeManager.h"
144 #endif
146 using namespace mozilla;
147 using namespace mozilla::dom;
149 static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
151 // NOTE: DEFAULT_SCRIPTABLE_FLAGS and DOM_DEFAULT_SCRIPTABLE_FLAGS
152 // are defined in nsIDOMClassInfo.h.
154 #define WINDOW_SCRIPTABLE_FLAGS \
155 (nsIXPCScriptable::WANT_PRECREATE | \
156 nsIXPCScriptable::WANT_POSTCREATE | \
157 nsIXPCScriptable::WANT_ENUMERATE | \
158 nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE | \
159 nsIXPCScriptable::IS_GLOBAL_OBJECT | \
160 nsIXPCScriptable::WANT_OUTER_OBJECT)
162 #define ARRAY_SCRIPTABLE_FLAGS \
163 (DOM_DEFAULT_SCRIPTABLE_FLAGS | \
164 nsIXPCScriptable::WANT_GETPROPERTY | \
165 nsIXPCScriptable::WANT_ENUMERATE)
167 #define EVENTTARGET_SCRIPTABLE_FLAGS \
168 (DOM_DEFAULT_SCRIPTABLE_FLAGS | \
169 nsIXPCScriptable::WANT_ADDPROPERTY)
171 #define DOMCLASSINFO_STANDARD_FLAGS \
172 (nsIClassInfo::MAIN_THREAD_ONLY | \
173 nsIClassInfo::DOM_OBJECT | \
174 nsIClassInfo::SINGLETON_CLASSINFO)
177 #ifdef DEBUG
178 #define NS_DEFINE_CLASSINFO_DATA_DEBUG(_class) \
179 eDOMClassInfo_##_class##_id,
180 #else
181 #define NS_DEFINE_CLASSINFO_DATA_DEBUG(_class) \
182 // nothing
183 #endif
186 * To generate the bitmap for a class that we're sure doesn't implement any of
187 * the interfaces in DOMCI_CASTABLE_INTERFACES.
189 #define DOMCI_DATA_NO_CLASS(_dom_class) \
190 const uint32_t kDOMClassInfo_##_dom_class##_interfaces = \
193 DOMCI_DATA_NO_CLASS(ContentFrameMessageManager)
194 DOMCI_DATA_NO_CLASS(ChromeMessageBroadcaster)
195 DOMCI_DATA_NO_CLASS(ChromeMessageSender)
197 DOMCI_DATA_NO_CLASS(DOMPrototype)
198 DOMCI_DATA_NO_CLASS(DOMConstructor)
200 DOMCI_DATA_NO_CLASS(UserDataHandler)
201 DOMCI_DATA_NO_CLASS(XULControlElement)
202 DOMCI_DATA_NO_CLASS(XULLabeledControlElement)
203 DOMCI_DATA_NO_CLASS(XULButtonElement)
204 DOMCI_DATA_NO_CLASS(XULCheckboxElement)
205 DOMCI_DATA_NO_CLASS(XULPopupElement)
207 #define NS_DEFINE_CLASSINFO_DATA_HELPER(_class, _helper, _flags, \
208 _chromeOnly, _allowXBL) \
209 { #_class, \
210 nullptr, \
211 { _helper::doCreate }, \
212 nullptr, \
213 nullptr, \
214 nullptr, \
215 _flags, \
216 true, \
217 0, \
218 _chromeOnly, \
219 _allowXBL, \
220 false, \
221 NS_DEFINE_CLASSINFO_DATA_DEBUG(_class) \
224 #define NS_DEFINE_CLASSINFO_DATA(_class, _helper, _flags) \
225 NS_DEFINE_CLASSINFO_DATA_HELPER(_class, _helper, _flags, false, false)
227 #define NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(_class, _helper, _flags) \
228 NS_DEFINE_CLASSINFO_DATA_HELPER(_class, _helper, _flags, true, false)
230 #define NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(_class, _helper, _flags) \
231 NS_DEFINE_CLASSINFO_DATA_HELPER(_class, _helper, _flags, true, true)
234 // This list of NS_DEFINE_CLASSINFO_DATA macros is what gives the DOM
235 // classes their correct behavior when used through XPConnect. The
236 // arguments that are passed to NS_DEFINE_CLASSINFO_DATA are
238 // 1. Class name as it should appear in JavaScript, this name is also
239 // used to find the id of the class in nsDOMClassInfo
240 // (i.e. e<classname>_id)
241 // 2. Scriptable helper class
242 // 3. nsIClassInfo/nsIXPCScriptable flags (i.e. for GetScriptableFlags)
244 static nsDOMClassInfoData sClassInfoData[] = {
245 // Base classes
247 // The Window class lets you QI into interfaces that are not in the
248 // flattened set (i.e. nsIXPCScriptable::CLASSINFO_INTERFACES_ONLY
249 // is not set), because of this make sure all scriptable interfaces
250 // that are implemented by nsGlobalWindow can securely be exposed
251 // to JS.
254 NS_DEFINE_CLASSINFO_DATA(Window, nsWindowSH,
255 DEFAULT_SCRIPTABLE_FLAGS |
256 WINDOW_SCRIPTABLE_FLAGS)
258 NS_DEFINE_CLASSINFO_DATA(DOMPrototype, nsDOMConstructorSH,
259 DOM_BASE_SCRIPTABLE_FLAGS |
260 nsIXPCScriptable::WANT_PRECREATE |
261 nsIXPCScriptable::WANT_NEWRESOLVE |
262 nsIXPCScriptable::WANT_HASINSTANCE |
263 nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE)
264 NS_DEFINE_CLASSINFO_DATA(DOMConstructor, nsDOMConstructorSH,
265 DOM_BASE_SCRIPTABLE_FLAGS |
266 nsIXPCScriptable::WANT_PRECREATE |
267 nsIXPCScriptable::WANT_NEWRESOLVE |
268 nsIXPCScriptable::WANT_HASINSTANCE |
269 nsIXPCScriptable::WANT_CALL |
270 nsIXPCScriptable::WANT_CONSTRUCT |
271 nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE)
273 // Misc Core related classes
275 // CSS classes
276 NS_DEFINE_CLASSINFO_DATA(CSSStyleRule, nsDOMGenericSH,
277 DOM_DEFAULT_SCRIPTABLE_FLAGS)
278 NS_DEFINE_CLASSINFO_DATA(CSSCharsetRule, nsDOMGenericSH,
279 DOM_DEFAULT_SCRIPTABLE_FLAGS)
280 NS_DEFINE_CLASSINFO_DATA(CSSImportRule, nsDOMGenericSH,
281 DOM_DEFAULT_SCRIPTABLE_FLAGS)
282 NS_DEFINE_CLASSINFO_DATA(CSSMediaRule, nsDOMGenericSH,
283 DOM_DEFAULT_SCRIPTABLE_FLAGS)
284 NS_DEFINE_CLASSINFO_DATA(CSSNameSpaceRule, nsDOMGenericSH,
285 DOM_DEFAULT_SCRIPTABLE_FLAGS)
287 // XUL classes
288 #ifdef MOZ_XUL
289 NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULCommandDispatcher, nsDOMGenericSH,
290 DOM_DEFAULT_SCRIPTABLE_FLAGS)
291 #endif
292 NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULControllers, nsNonDOMObjectSH,
293 DEFAULT_SCRIPTABLE_FLAGS)
294 NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(BoxObject, nsDOMGenericSH,
295 DEFAULT_SCRIPTABLE_FLAGS)
296 #ifdef MOZ_XUL
297 NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(TreeSelection, nsDOMGenericSH,
298 DEFAULT_SCRIPTABLE_FLAGS)
299 NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(TreeContentView, nsDOMGenericSH,
300 DEFAULT_SCRIPTABLE_FLAGS)
301 #endif
303 // DOM Chrome Window class.
304 NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(ChromeWindow, nsWindowSH,
305 DEFAULT_SCRIPTABLE_FLAGS |
306 WINDOW_SCRIPTABLE_FLAGS)
308 #ifdef MOZ_XUL
309 NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULTemplateBuilder, nsDOMGenericSH,
310 DEFAULT_SCRIPTABLE_FLAGS)
312 NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULTreeBuilder, nsDOMGenericSH,
313 DEFAULT_SCRIPTABLE_FLAGS)
314 #endif
316 #ifdef MOZ_XUL
317 NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(TreeColumn, nsDOMGenericSH,
318 DEFAULT_SCRIPTABLE_FLAGS)
319 #endif
321 NS_DEFINE_CLASSINFO_DATA(CSSMozDocumentRule, nsDOMGenericSH,
322 DOM_DEFAULT_SCRIPTABLE_FLAGS)
324 NS_DEFINE_CLASSINFO_DATA(CSSSupportsRule, nsDOMGenericSH,
325 DOM_DEFAULT_SCRIPTABLE_FLAGS)
327 NS_DEFINE_CLASSINFO_DATA(XSLTProcessor, nsDOMGenericSH,
328 DOM_DEFAULT_SCRIPTABLE_FLAGS)
330 NS_DEFINE_CLASSINFO_DATA(XPathNSResolver, nsDOMGenericSH,
331 DOM_DEFAULT_SCRIPTABLE_FLAGS)
333 NS_DEFINE_CLASSINFO_DATA(Blob, nsDOMGenericSH,
334 DOM_DEFAULT_SCRIPTABLE_FLAGS)
335 NS_DEFINE_CLASSINFO_DATA(File, nsDOMGenericSH,
336 DOM_DEFAULT_SCRIPTABLE_FLAGS)
338 NS_DEFINE_CLASSINFO_DATA(ModalContentWindow, nsWindowSH,
339 DEFAULT_SCRIPTABLE_FLAGS |
340 WINDOW_SCRIPTABLE_FLAGS)
342 NS_DEFINE_CLASSINFO_DATA(MozSmsMessage, nsDOMGenericSH,
343 DOM_DEFAULT_SCRIPTABLE_FLAGS)
345 NS_DEFINE_CLASSINFO_DATA(MozMmsMessage, nsDOMGenericSH,
346 DOM_DEFAULT_SCRIPTABLE_FLAGS)
348 NS_DEFINE_CLASSINFO_DATA(MozMobileMessageThread, nsDOMGenericSH,
349 DOM_DEFAULT_SCRIPTABLE_FLAGS)
351 NS_DEFINE_CLASSINFO_DATA(CSSFontFaceRule, nsDOMGenericSH,
352 DOM_DEFAULT_SCRIPTABLE_FLAGS)
354 NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ContentFrameMessageManager, nsEventTargetSH,
355 DOM_DEFAULT_SCRIPTABLE_FLAGS |
356 nsIXPCScriptable::IS_GLOBAL_OBJECT)
357 NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ChromeMessageBroadcaster, nsDOMGenericSH,
358 DOM_DEFAULT_SCRIPTABLE_FLAGS)
359 NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ChromeMessageSender, nsDOMGenericSH,
360 DOM_DEFAULT_SCRIPTABLE_FLAGS)
363 NS_DEFINE_CLASSINFO_DATA(MozCSSKeyframeRule, nsDOMGenericSH,
364 DOM_DEFAULT_SCRIPTABLE_FLAGS)
365 NS_DEFINE_CLASSINFO_DATA(MozCSSKeyframesRule, nsDOMGenericSH,
366 DOM_DEFAULT_SCRIPTABLE_FLAGS)
368 NS_DEFINE_CLASSINFO_DATA(CSSCounterStyleRule, nsDOMGenericSH,
369 DOM_DEFAULT_SCRIPTABLE_FLAGS)
371 NS_DEFINE_CLASSINFO_DATA(CSSPageRule, nsDOMGenericSH,
372 DOM_DEFAULT_SCRIPTABLE_FLAGS)
374 NS_DEFINE_CLASSINFO_DATA(CSSFontFeatureValuesRule, nsDOMGenericSH,
375 DOM_DEFAULT_SCRIPTABLE_FLAGS)
377 NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(UserDataHandler, nsDOMGenericSH,
378 DOM_DEFAULT_SCRIPTABLE_FLAGS)
379 NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULControlElement, nsDOMGenericSH,
380 DOM_DEFAULT_SCRIPTABLE_FLAGS)
381 NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULLabeledControlElement, nsDOMGenericSH,
382 DOM_DEFAULT_SCRIPTABLE_FLAGS)
383 NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULButtonElement, nsDOMGenericSH,
384 DOM_DEFAULT_SCRIPTABLE_FLAGS)
385 NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULCheckboxElement, nsDOMGenericSH,
386 DOM_DEFAULT_SCRIPTABLE_FLAGS)
387 NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULPopupElement, nsDOMGenericSH,
388 DOM_DEFAULT_SCRIPTABLE_FLAGS)
391 #define NS_DEFINE_CONTRACT_CTOR(_class, _contract_id) \
392 static nsresult \
393 _class##Ctor(nsISupports** aInstancePtrResult) \
395 nsresult rv = NS_OK; \
396 nsCOMPtr<nsISupports> native = do_CreateInstance(_contract_id, &rv); \
397 native.forget(aInstancePtrResult); \
398 return rv; \
401 NS_DEFINE_CONTRACT_CTOR(XSLTProcessor,
402 "@mozilla.org/document-transformer;1?type=xslt")
404 #undef NS_DEFINE_CONTRACT_CTOR
406 struct nsConstructorFuncMapData
408 int32_t mDOMClassInfoID;
409 nsDOMConstructorFunc mConstructorFunc;
412 #define NS_DEFINE_CONSTRUCTOR_FUNC_DATA(_class, _func) \
413 { eDOMClassInfo_##_class##_id, _func },
415 static const nsConstructorFuncMapData kConstructorFuncMap[] =
417 NS_DEFINE_CONSTRUCTOR_FUNC_DATA(Blob, DOMMultipartFileImpl::NewBlob)
418 NS_DEFINE_CONSTRUCTOR_FUNC_DATA(File, DOMMultipartFileImpl::NewFile)
419 NS_DEFINE_CONSTRUCTOR_FUNC_DATA(XSLTProcessor, XSLTProcessorCtor)
421 #undef NS_DEFINE_CONSTRUCTOR_FUNC_DATA
423 nsIXPConnect *nsDOMClassInfo::sXPConnect = nullptr;
424 bool nsDOMClassInfo::sIsInitialized = false;
427 jsid nsDOMClassInfo::sLocation_id = JSID_VOID;
428 jsid nsDOMClassInfo::sConstructor_id = JSID_VOID;
429 jsid nsDOMClassInfo::sTop_id = JSID_VOID;
430 jsid nsDOMClassInfo::sDocument_id = JSID_VOID;
431 jsid nsDOMClassInfo::sWrappedJSObject_id = JSID_VOID;
433 static const JSClass *sObjectClass = nullptr;
436 * Set our JSClass pointer for the Object class
438 static void
439 FindObjectClass(JSContext* cx, JSObject* aGlobalObject)
441 NS_ASSERTION(!sObjectClass,
442 "Double set of sObjectClass");
443 JS::Rooted<JSObject*> obj(cx), proto(cx, aGlobalObject);
444 do {
445 obj = proto;
446 js::GetObjectProto(cx, obj, &proto);
447 } while (proto);
449 sObjectClass = js::GetObjectJSClass(obj);
452 static inline nsresult
453 WrapNative(JSContext *cx, nsISupports *native,
454 nsWrapperCache *cache, const nsIID* aIID, JS::MutableHandle<JS::Value> vp,
455 bool aAllowWrapping)
457 if (!native) {
458 vp.setNull();
460 return NS_OK;
463 JSObject *wrapper = xpc_FastGetCachedWrapper(cx, cache, vp);
464 if (wrapper) {
465 return NS_OK;
468 JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
469 return nsDOMClassInfo::XPConnect()->WrapNativeToJSVal(cx, scope, native,
470 cache, aIID,
471 aAllowWrapping, vp);
474 static inline nsresult
475 WrapNative(JSContext *cx, nsISupports *native, const nsIID* aIID,
476 bool aAllowWrapping, JS::MutableHandle<JS::Value> vp)
478 return WrapNative(cx, native, nullptr, aIID, vp, aAllowWrapping);
481 // Same as the WrapNative above, but use these if aIID is nsISupports' IID.
482 static inline nsresult
483 WrapNative(JSContext *cx, nsISupports *native,
484 bool aAllowWrapping, JS::MutableHandle<JS::Value> vp)
486 return WrapNative(cx, native, nullptr, nullptr, vp, aAllowWrapping);
489 // Helper to handle torn-down inner windows.
490 static inline nsresult
491 SetParentToWindow(nsGlobalWindow *win, JSObject **parent)
493 MOZ_ASSERT(win);
494 MOZ_ASSERT(win->IsInnerWindow());
495 *parent = win->FastGetGlobalJSObject();
497 if (MOZ_UNLIKELY(!*parent)) {
498 // The inner window has been torn down. The scope is dying, so don't create
499 // any new wrappers.
500 return NS_ERROR_FAILURE;
502 return NS_OK;
505 // static
507 nsISupports *
508 nsDOMClassInfo::GetNative(nsIXPConnectWrappedNative *wrapper, JSObject *obj)
510 return wrapper ? wrapper->Native() : static_cast<nsISupports*>(js::GetObjectPrivate(obj));
513 nsresult
514 nsDOMClassInfo::DefineStaticJSVals(JSContext *cx)
516 #define SET_JSID_TO_STRING(_id, _cx, _str) \
517 if (JSString *str = ::JS_InternString(_cx, _str)) \
518 _id = INTERNED_STRING_TO_JSID(_cx, str); \
519 else \
520 return NS_ERROR_OUT_OF_MEMORY;
522 SET_JSID_TO_STRING(sLocation_id, cx, "location");
523 SET_JSID_TO_STRING(sConstructor_id, cx, "constructor");
524 SET_JSID_TO_STRING(sTop_id, cx, "top");
525 SET_JSID_TO_STRING(sDocument_id, cx, "document");
526 SET_JSID_TO_STRING(sWrappedJSObject_id, cx, "wrappedJSObject");
528 return NS_OK;
531 // static
532 bool
533 nsDOMClassInfo::ObjectIsNativeWrapper(JSContext* cx, JSObject* obj)
535 return xpc::WrapperFactory::IsXrayWrapper(obj) &&
536 xpc::AccessCheck::wrapperSubsumes(obj);
539 nsDOMClassInfo::nsDOMClassInfo(nsDOMClassInfoData* aData) : mData(aData)
543 nsDOMClassInfo::~nsDOMClassInfo()
545 if (IS_EXTERNAL(mData->mCachedClassInfo)) {
546 // Some compilers don't like delete'ing a const nsDOMClassInfo*
547 nsDOMClassInfoData* data = const_cast<nsDOMClassInfoData*>(mData);
548 delete static_cast<nsExternalDOMClassInfoData*>(data);
552 NS_IMPL_ADDREF(nsDOMClassInfo)
553 NS_IMPL_RELEASE(nsDOMClassInfo)
555 NS_INTERFACE_MAP_BEGIN(nsDOMClassInfo)
556 if (aIID.Equals(NS_GET_IID(nsXPCClassInfo)))
557 foundInterface = static_cast<nsIClassInfo*>(
558 static_cast<nsXPCClassInfo*>(this));
559 else
560 NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable)
561 NS_INTERFACE_MAP_ENTRY(nsIClassInfo)
562 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIClassInfo)
563 NS_INTERFACE_MAP_END
566 static const JSClass sDOMConstructorProtoClass = {
567 "DOM Constructor.prototype", 0,
568 JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
569 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, nullptr
573 static const char *
574 CutPrefix(const char *aName) {
575 static const char prefix_nsIDOM[] = "nsIDOM";
576 static const char prefix_nsI[] = "nsI";
578 if (strncmp(aName, prefix_nsIDOM, sizeof(prefix_nsIDOM) - 1) == 0) {
579 return aName + sizeof(prefix_nsIDOM) - 1;
582 if (strncmp(aName, prefix_nsI, sizeof(prefix_nsI) - 1) == 0) {
583 return aName + sizeof(prefix_nsI) - 1;
586 return aName;
589 // static
590 nsresult
591 nsDOMClassInfo::RegisterClassProtos(int32_t aClassInfoID)
593 nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
594 NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
595 bool found_old;
597 const nsIID *primary_iid = sClassInfoData[aClassInfoID].mProtoChainInterface;
599 if (!primary_iid || primary_iid == &NS_GET_IID(nsISupports)) {
600 return NS_OK;
603 nsCOMPtr<nsIInterfaceInfoManager>
604 iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
605 NS_ENSURE_TRUE(iim, NS_ERROR_NOT_AVAILABLE);
607 nsCOMPtr<nsIInterfaceInfo> if_info;
608 bool first = true;
610 iim->GetInfoForIID(primary_iid, getter_AddRefs(if_info));
612 while (if_info) {
613 const nsIID *iid = nullptr;
615 if_info->GetIIDShared(&iid);
616 NS_ENSURE_TRUE(iid, NS_ERROR_UNEXPECTED);
618 if (iid->Equals(NS_GET_IID(nsISupports))) {
619 break;
622 const char *name = nullptr;
623 if_info->GetNameShared(&name);
624 NS_ENSURE_TRUE(name, NS_ERROR_UNEXPECTED);
626 nameSpaceManager->RegisterClassProto(CutPrefix(name), iid, &found_old);
628 if (first) {
629 first = false;
630 } else if (found_old) {
631 break;
634 nsCOMPtr<nsIInterfaceInfo> tmp(if_info);
635 tmp->GetParent(getter_AddRefs(if_info));
638 return NS_OK;
641 // static
642 nsresult
643 nsDOMClassInfo::RegisterExternalClasses()
645 nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
646 NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
648 nsCOMPtr<nsIComponentRegistrar> registrar;
649 nsresult rv = NS_GetComponentRegistrar(getter_AddRefs(registrar));
650 NS_ENSURE_SUCCESS(rv, rv);
652 nsCOMPtr<nsICategoryManager> cm =
653 do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
654 NS_ENSURE_SUCCESS(rv, rv);
656 nsCOMPtr<nsISimpleEnumerator> e;
657 rv = cm->EnumerateCategory(JAVASCRIPT_DOM_CLASS, getter_AddRefs(e));
658 NS_ENSURE_SUCCESS(rv, rv);
660 nsXPIDLCString contractId;
661 nsAutoCString categoryEntry;
662 nsCOMPtr<nsISupports> entry;
664 while (NS_SUCCEEDED(e->GetNext(getter_AddRefs(entry)))) {
665 nsCOMPtr<nsISupportsCString> category(do_QueryInterface(entry));
667 if (!category) {
668 NS_WARNING("Category entry not an nsISupportsCString!");
669 continue;
672 rv = category->GetData(categoryEntry);
674 cm->GetCategoryEntry(JAVASCRIPT_DOM_CLASS, categoryEntry.get(),
675 getter_Copies(contractId));
676 NS_ENSURE_SUCCESS(rv, rv);
678 nsCID *cid;
679 rv = registrar->ContractIDToCID(contractId, &cid);
680 if (NS_FAILED(rv)) {
681 NS_WARNING("Bad contract id registered with the script namespace manager");
682 continue;
685 rv = nameSpaceManager->RegisterExternalClassName(categoryEntry.get(), *cid);
686 nsMemory::Free(cid);
687 NS_ENSURE_SUCCESS(rv, rv);
690 return nameSpaceManager->RegisterExternalInterfaces(true);
693 #define _DOM_CLASSINFO_MAP_BEGIN(_class, _ifptr, _has_class_if) \
695 nsDOMClassInfoData &d = sClassInfoData[eDOMClassInfo_##_class##_id]; \
696 d.mProtoChainInterface = _ifptr; \
697 d.mHasClassInterface = _has_class_if; \
698 d.mInterfacesBitmap = kDOMClassInfo_##_class##_interfaces; \
699 static const nsIID *interface_list[] = {
701 #define DOM_CLASSINFO_MAP_BEGIN(_class, _interface) \
702 _DOM_CLASSINFO_MAP_BEGIN(_class, &NS_GET_IID(_interface), true)
704 #define DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(_class, _interface) \
705 _DOM_CLASSINFO_MAP_BEGIN(_class, &NS_GET_IID(_interface), false)
707 #define DOM_CLASSINFO_MAP_ENTRY(_if) \
708 &NS_GET_IID(_if),
710 #define DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(_if, _cond) \
711 (_cond) ? &NS_GET_IID(_if) : nullptr,
713 #define DOM_CLASSINFO_MAP_END \
714 nullptr \
715 }; \
717 /* Compact the interface list */ \
718 size_t count = ArrayLength(interface_list); \
719 /* count is the number of array entries, which is one greater than the */ \
720 /* number of interfaces due to the terminating null */ \
721 for (size_t i = 0; i < count - 1; ++i) { \
722 if (!interface_list[i]) { \
723 /* We are moving the element at index i+1 and successors, */ \
724 /* so we must move only count - (i+1) elements total. */ \
725 memmove(&interface_list[i], &interface_list[i+1], \
726 sizeof(nsIID*) * (count - (i+1))); \
727 /* Make sure to examine the new pointer we ended up with at this */ \
728 /* slot, since it may be null too */ \
729 --i; \
730 --count; \
734 d.mInterfaces = interface_list; \
737 #ifdef MOZ_B2G
738 #define DOM_CLASSINFO_WINDOW_MAP_ENTRIES \
739 DOM_CLASSINFO_MAP_ENTRY(nsIDOMWindow) \
740 DOM_CLASSINFO_MAP_ENTRY(nsIDOMWindowB2G) \
741 DOM_CLASSINFO_MAP_ENTRY(nsIDOMJSWindow) \
742 DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) \
743 DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers) \
744 DOM_CLASSINFO_MAP_ENTRY(nsIDOMWindowPerformance) \
745 DOM_CLASSINFO_MAP_ENTRY(nsIInterfaceRequestor) \
746 DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsITouchEventReceiver, \
747 TouchEvent::PrefEnabled())
748 #else // !MOZ_B2G
749 #define DOM_CLASSINFO_WINDOW_MAP_ENTRIES \
750 DOM_CLASSINFO_MAP_ENTRY(nsIDOMWindow) \
751 DOM_CLASSINFO_MAP_ENTRY(nsIDOMJSWindow) \
752 DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) \
753 DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers) \
754 DOM_CLASSINFO_MAP_ENTRY(nsIDOMWindowPerformance) \
755 DOM_CLASSINFO_MAP_ENTRY(nsIInterfaceRequestor) \
756 DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsITouchEventReceiver, \
757 TouchEvent::PrefEnabled())
758 #endif // MOZ_B2G
760 nsresult
761 nsDOMClassInfo::Init()
763 /* Errors that can trigger early returns are done first,
764 otherwise nsDOMClassInfo is left in a half inited state. */
765 static_assert(sizeof(uintptr_t) == sizeof(void*),
766 "BAD! You'll need to adjust the size of uintptr_t to the "
767 "size of a pointer on your platform.");
769 NS_ENSURE_TRUE(!sIsInitialized, NS_ERROR_ALREADY_INITIALIZED);
771 nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
772 NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
774 NS_ADDREF(sXPConnect = nsContentUtils::XPConnect());
776 nsCOMPtr<nsIXPCFunctionThisTranslator> elt = new nsEventListenerThisTranslator();
777 sXPConnect->SetFunctionThisTranslator(NS_GET_IID(nsIDOMEventListener), elt);
779 AutoSafeJSContext cx;
781 DOM_CLASSINFO_MAP_BEGIN(Window, nsIDOMWindow)
782 DOM_CLASSINFO_WINDOW_MAP_ENTRIES
783 #ifdef MOZ_WEBSPEECH
784 DOM_CLASSINFO_MAP_ENTRY(nsISpeechSynthesisGetter)
785 #endif
786 DOM_CLASSINFO_MAP_END
788 DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(DOMPrototype, nsIDOMDOMConstructor)
789 DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMConstructor)
790 DOM_CLASSINFO_MAP_END
792 DOM_CLASSINFO_MAP_BEGIN(DOMConstructor, nsIDOMDOMConstructor)
793 DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMConstructor)
794 DOM_CLASSINFO_MAP_END
796 DOM_CLASSINFO_MAP_BEGIN(CSSStyleRule, nsIDOMCSSStyleRule)
797 DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSStyleRule)
798 DOM_CLASSINFO_MAP_END
800 DOM_CLASSINFO_MAP_BEGIN(CSSCharsetRule, nsIDOMCSSCharsetRule)
801 DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSCharsetRule)
802 DOM_CLASSINFO_MAP_END
804 DOM_CLASSINFO_MAP_BEGIN(CSSImportRule, nsIDOMCSSImportRule)
805 DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSImportRule)
806 DOM_CLASSINFO_MAP_END
808 DOM_CLASSINFO_MAP_BEGIN(CSSMediaRule, nsIDOMCSSMediaRule)
809 DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSMediaRule)
810 DOM_CLASSINFO_MAP_END
812 DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(CSSNameSpaceRule, nsIDOMCSSRule)
813 DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSRule)
814 DOM_CLASSINFO_MAP_END
816 #ifdef MOZ_XUL
817 DOM_CLASSINFO_MAP_BEGIN(XULCommandDispatcher, nsIDOMXULCommandDispatcher)
818 DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULCommandDispatcher)
819 DOM_CLASSINFO_MAP_END
820 #endif
822 DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULControllers, nsIControllers)
823 DOM_CLASSINFO_MAP_ENTRY(nsIControllers)
824 DOM_CLASSINFO_MAP_END
826 DOM_CLASSINFO_MAP_BEGIN(BoxObject, nsIBoxObject)
827 DOM_CLASSINFO_MAP_ENTRY(nsIBoxObject)
828 DOM_CLASSINFO_MAP_END
830 #ifdef MOZ_XUL
831 DOM_CLASSINFO_MAP_BEGIN(TreeSelection, nsITreeSelection)
832 DOM_CLASSINFO_MAP_ENTRY(nsITreeSelection)
833 DOM_CLASSINFO_MAP_END
835 DOM_CLASSINFO_MAP_BEGIN(TreeContentView, nsITreeContentView)
836 DOM_CLASSINFO_MAP_ENTRY(nsITreeContentView)
837 DOM_CLASSINFO_MAP_ENTRY(nsITreeView)
838 DOM_CLASSINFO_MAP_END
839 #endif
841 DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ChromeWindow, nsIDOMWindow)
842 DOM_CLASSINFO_WINDOW_MAP_ENTRIES
843 DOM_CLASSINFO_MAP_ENTRY(nsIDOMChromeWindow)
844 #ifdef MOZ_WEBSPEECH
845 DOM_CLASSINFO_MAP_ENTRY(nsISpeechSynthesisGetter)
846 #endif
847 DOM_CLASSINFO_MAP_END
849 #ifdef MOZ_XUL
850 DOM_CLASSINFO_MAP_BEGIN(XULTemplateBuilder, nsIXULTemplateBuilder)
851 DOM_CLASSINFO_MAP_ENTRY(nsIXULTemplateBuilder)
852 DOM_CLASSINFO_MAP_END
854 DOM_CLASSINFO_MAP_BEGIN(XULTreeBuilder, nsIXULTreeBuilder)
855 DOM_CLASSINFO_MAP_ENTRY(nsIXULTreeBuilder)
856 DOM_CLASSINFO_MAP_ENTRY(nsIXULTemplateBuilder)
857 DOM_CLASSINFO_MAP_ENTRY(nsITreeView)
858 DOM_CLASSINFO_MAP_END
859 #endif
861 #ifdef MOZ_XUL
862 DOM_CLASSINFO_MAP_BEGIN(TreeColumn, nsITreeColumn)
863 DOM_CLASSINFO_MAP_ENTRY(nsITreeColumn)
864 DOM_CLASSINFO_MAP_END
865 #endif
867 DOM_CLASSINFO_MAP_BEGIN(CSSMozDocumentRule, nsIDOMCSSMozDocumentRule)
868 DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSMozDocumentRule)
869 DOM_CLASSINFO_MAP_END
871 DOM_CLASSINFO_MAP_BEGIN(CSSSupportsRule, nsIDOMCSSSupportsRule)
872 DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSSupportsRule)
873 DOM_CLASSINFO_MAP_END
875 DOM_CLASSINFO_MAP_BEGIN(XSLTProcessor, nsIXSLTProcessor)
876 DOM_CLASSINFO_MAP_ENTRY(nsIXSLTProcessor)
877 DOM_CLASSINFO_MAP_ENTRY(nsIXSLTProcessorPrivate)
878 DOM_CLASSINFO_MAP_END
880 DOM_CLASSINFO_MAP_BEGIN(XPathNSResolver, nsIDOMXPathNSResolver)
881 DOM_CLASSINFO_MAP_ENTRY(nsIDOMXPathNSResolver)
882 DOM_CLASSINFO_MAP_END
884 DOM_CLASSINFO_MAP_BEGIN(Blob, nsIDOMBlob)
885 DOM_CLASSINFO_MAP_ENTRY(nsIDOMBlob)
886 DOM_CLASSINFO_MAP_END
888 DOM_CLASSINFO_MAP_BEGIN(File, nsIDOMFile)
889 DOM_CLASSINFO_MAP_ENTRY(nsIDOMBlob)
890 DOM_CLASSINFO_MAP_ENTRY(nsIDOMFile)
891 DOM_CLASSINFO_MAP_END
893 DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ModalContentWindow, nsIDOMWindow)
894 DOM_CLASSINFO_WINDOW_MAP_ENTRIES
895 DOM_CLASSINFO_MAP_ENTRY(nsIDOMModalContentWindow)
896 #ifdef MOZ_WEBSPEECH
897 DOM_CLASSINFO_MAP_ENTRY(nsISpeechSynthesisGetter)
898 #endif
899 DOM_CLASSINFO_MAP_END
901 DOM_CLASSINFO_MAP_BEGIN(MozSmsMessage, nsIDOMMozSmsMessage)
902 DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozSmsMessage)
903 DOM_CLASSINFO_MAP_END
905 DOM_CLASSINFO_MAP_BEGIN(MozMmsMessage, nsIDOMMozMmsMessage)
906 DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozMmsMessage)
907 DOM_CLASSINFO_MAP_END
909 DOM_CLASSINFO_MAP_BEGIN(MozMobileMessageThread, nsIDOMMozMobileMessageThread)
910 DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozMobileMessageThread)
911 DOM_CLASSINFO_MAP_END
913 DOM_CLASSINFO_MAP_BEGIN(CSSFontFaceRule, nsIDOMCSSFontFaceRule)
914 DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSFontFaceRule)
915 DOM_CLASSINFO_MAP_END
917 DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ContentFrameMessageManager, nsISupports)
918 DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
919 DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager)
920 DOM_CLASSINFO_MAP_ENTRY(nsIMessageSender)
921 DOM_CLASSINFO_MAP_ENTRY(nsISyncMessageSender)
922 DOM_CLASSINFO_MAP_ENTRY(nsIContentFrameMessageManager)
923 DOM_CLASSINFO_MAP_END
925 DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ChromeMessageBroadcaster, nsISupports)
926 DOM_CLASSINFO_MAP_ENTRY(nsIFrameScriptLoader)
927 DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager)
928 DOM_CLASSINFO_MAP_ENTRY(nsIMessageBroadcaster)
929 DOM_CLASSINFO_MAP_END
931 DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ChromeMessageSender, nsISupports)
932 DOM_CLASSINFO_MAP_ENTRY(nsIProcessChecker)
933 DOM_CLASSINFO_MAP_ENTRY(nsIFrameScriptLoader)
934 DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager)
935 DOM_CLASSINFO_MAP_ENTRY(nsIMessageSender)
936 DOM_CLASSINFO_MAP_END
938 DOM_CLASSINFO_MAP_BEGIN(MozCSSKeyframeRule, nsIDOMMozCSSKeyframeRule)
939 DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozCSSKeyframeRule)
940 DOM_CLASSINFO_MAP_END
942 DOM_CLASSINFO_MAP_BEGIN(MozCSSKeyframesRule, nsIDOMMozCSSKeyframesRule)
943 DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozCSSKeyframesRule)
944 DOM_CLASSINFO_MAP_END
946 DOM_CLASSINFO_MAP_BEGIN(CSSCounterStyleRule, nsIDOMCSSCounterStyleRule)
947 DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSCounterStyleRule)
948 DOM_CLASSINFO_MAP_END
950 DOM_CLASSINFO_MAP_BEGIN(CSSPageRule, nsIDOMCSSPageRule)
951 DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSPageRule)
952 DOM_CLASSINFO_MAP_END
954 DOM_CLASSINFO_MAP_BEGIN(CSSFontFeatureValuesRule, nsIDOMCSSFontFeatureValuesRule)
955 DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSFontFeatureValuesRule)
956 DOM_CLASSINFO_MAP_END
958 DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(UserDataHandler, nsIDOMUserDataHandler)
959 DOM_CLASSINFO_MAP_ENTRY(nsIDOMUserDataHandler)
960 DOM_CLASSINFO_MAP_END
962 DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULControlElement, nsIDOMXULControlElement)
963 DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULControlElement)
964 DOM_CLASSINFO_MAP_END
966 DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULLabeledControlElement, nsIDOMXULLabeledControlElement)
967 DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULLabeledControlElement)
968 DOM_CLASSINFO_MAP_END
970 DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULButtonElement, nsIDOMXULButtonElement)
971 DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULButtonElement)
972 DOM_CLASSINFO_MAP_END
974 DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULCheckboxElement, nsIDOMXULCheckboxElement)
975 DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULCheckboxElement)
976 DOM_CLASSINFO_MAP_END
978 DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULPopupElement, nsIDOMXULPopupElement)
979 DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULPopupElement)
980 DOM_CLASSINFO_MAP_END
982 static_assert(MOZ_ARRAY_LENGTH(sClassInfoData) == eDOMClassInfoIDCount,
983 "The number of items in sClassInfoData doesn't match the "
984 "number of nsIDOMClassInfo ID's, this is bad! Fix it!");
986 #ifdef DEBUG
987 for (size_t i = 0; i < eDOMClassInfoIDCount; i++) {
988 if (!sClassInfoData[i].u.mConstructorFptr ||
989 sClassInfoData[i].mDebugID != i) {
990 MOZ_CRASH("Class info data out of sync, you forgot to update "
991 "nsDOMClassInfo.h and nsDOMClassInfo.cpp! Fix this, "
992 "mozilla will not work without this fixed!");
996 for (size_t i = 0; i < eDOMClassInfoIDCount; i++) {
997 if (!sClassInfoData[i].mInterfaces) {
998 MOZ_CRASH("Class info data without an interface list! Fix this, "
999 "mozilla will not work without this fixed!");
1002 #endif
1004 // Initialize static JSString's
1005 DefineStaticJSVals(cx);
1007 int32_t i;
1009 for (i = 0; i < eDOMClassInfoIDCount; ++i) {
1010 if (i == eDOMClassInfo_DOMPrototype_id) {
1011 continue;
1014 nsDOMClassInfoData& data = sClassInfoData[i];
1015 nameSpaceManager->RegisterClassName(data.mName, i, data.mChromeOnly,
1016 data.mAllowXBL, &data.mNameUTF16);
1019 for (i = 0; i < eDOMClassInfoIDCount; ++i) {
1020 RegisterClassProtos(i);
1023 RegisterExternalClasses();
1025 sIsInitialized = true;
1027 return NS_OK;
1030 NS_IMETHODIMP
1031 nsDOMClassInfo::GetInterfaces(uint32_t *aCount, nsIID ***aArray)
1033 uint32_t count = 0;
1035 while (mData->mInterfaces[count]) {
1036 count++;
1039 *aCount = count;
1041 if (!count) {
1042 *aArray = nullptr;
1044 return NS_OK;
1047 *aArray = static_cast<nsIID **>(nsMemory::Alloc(count * sizeof(nsIID *)));
1048 NS_ENSURE_TRUE(*aArray, NS_ERROR_OUT_OF_MEMORY);
1050 uint32_t i;
1051 for (i = 0; i < count; i++) {
1052 nsIID *iid = static_cast<nsIID *>(nsMemory::Clone(mData->mInterfaces[i],
1053 sizeof(nsIID)));
1055 if (!iid) {
1056 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, *aArray);
1058 return NS_ERROR_OUT_OF_MEMORY;
1061 *((*aArray) + i) = iid;
1064 return NS_OK;
1067 NS_IMETHODIMP
1068 nsDOMClassInfo::GetHelperForLanguage(uint32_t language, nsISupports **_retval)
1070 if (language == nsIProgrammingLanguage::JAVASCRIPT) {
1071 *_retval = static_cast<nsIXPCScriptable *>(this);
1073 NS_ADDREF(*_retval);
1074 } else {
1075 *_retval = nullptr;
1078 return NS_OK;
1081 NS_IMETHODIMP
1082 nsDOMClassInfo::GetContractID(char **aContractID)
1084 *aContractID = nullptr;
1086 return NS_OK;
1089 NS_IMETHODIMP
1090 nsDOMClassInfo::GetClassDescription(char **aClassDescription)
1092 return GetClassName(aClassDescription);
1095 NS_IMETHODIMP
1096 nsDOMClassInfo::GetClassID(nsCID **aClassID)
1098 *aClassID = nullptr;
1099 return NS_OK;
1102 NS_IMETHODIMP
1103 nsDOMClassInfo::GetClassIDNoAlloc(nsCID *aClassID)
1105 return NS_ERROR_NOT_AVAILABLE;
1108 NS_IMETHODIMP
1109 nsDOMClassInfo::GetImplementationLanguage(uint32_t *aImplLanguage)
1111 *aImplLanguage = nsIProgrammingLanguage::CPLUSPLUS;
1113 return NS_OK;
1116 NS_IMETHODIMP
1117 nsDOMClassInfo::GetFlags(uint32_t *aFlags)
1119 *aFlags = DOMCLASSINFO_STANDARD_FLAGS;
1121 return NS_OK;
1124 // nsIXPCScriptable
1126 NS_IMETHODIMP
1127 nsDOMClassInfo::GetClassName(char **aClassName)
1129 *aClassName = NS_strdup(mData->mName);
1131 return NS_OK;
1134 // virtual
1135 uint32_t
1136 nsDOMClassInfo::GetScriptableFlags()
1138 return mData->mScriptableFlags;
1141 NS_IMETHODIMP
1142 nsDOMClassInfo::PreCreate(nsISupports *nativeObj, JSContext *cx,
1143 JSObject *globalObj, JSObject **parentObj)
1145 *parentObj = globalObj;
1146 return NS_OK;
1149 NS_IMETHODIMP
1150 nsDOMClassInfo::Create(nsIXPConnectWrappedNative *wrapper,
1151 JSContext *cx, JSObject *obj)
1153 NS_WARNING("nsDOMClassInfo::Create Don't call me!");
1155 return NS_ERROR_UNEXPECTED;
1158 NS_IMETHODIMP
1159 nsDOMClassInfo::PostCreate(nsIXPConnectWrappedNative *wrapper,
1160 JSContext *cx, JSObject *obj)
1162 NS_WARNING("nsDOMClassInfo::PostCreate Don't call me!");
1164 return NS_ERROR_UNEXPECTED;
1167 NS_IMETHODIMP
1168 nsDOMClassInfo::PostTransplant(nsIXPConnectWrappedNative *wrapper,
1169 JSContext *cx, JSObject *obj)
1171 MOZ_CRASH("nsDOMClassInfo::PostTransplant Don't call me!");
1174 NS_IMETHODIMP
1175 nsDOMClassInfo::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
1176 JSObject *obj, jsid id, jsval *vp,
1177 bool *_retval)
1179 NS_WARNING("nsDOMClassInfo::AddProperty Don't call me!");
1181 return NS_ERROR_UNEXPECTED;
1184 NS_IMETHODIMP
1185 nsDOMClassInfo::DelProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
1186 JSObject *obj, jsid id, bool *_retval)
1188 NS_WARNING("nsDOMClassInfo::DelProperty Don't call me!");
1190 return NS_ERROR_UNEXPECTED;
1193 NS_IMETHODIMP
1194 nsDOMClassInfo::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
1195 JSObject *obj, jsid id, jsval *vp,
1196 bool *_retval)
1198 NS_WARNING("nsDOMClassInfo::GetProperty Don't call me!");
1200 return NS_OK;
1203 NS_IMETHODIMP
1204 nsDOMClassInfo::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
1205 JSObject *obj, jsid id, jsval *vp,
1206 bool *_retval)
1208 NS_WARNING("nsDOMClassInfo::SetProperty Don't call me!");
1210 return NS_ERROR_UNEXPECTED;
1213 NS_IMETHODIMP
1214 nsDOMClassInfo::Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
1215 JSObject *obj, bool *_retval)
1217 return NS_OK;
1220 NS_IMETHODIMP
1221 nsDOMClassInfo::NewEnumerate(nsIXPConnectWrappedNative *wrapper,
1222 JSContext *cx, JSObject *obj, uint32_t enum_op,
1223 jsval *statep, jsid *idp, bool *_retval)
1225 NS_WARNING("nsDOMClassInfo::NewEnumerate Don't call me!");
1227 return NS_ERROR_UNEXPECTED;
1230 nsresult
1231 nsDOMClassInfo::ResolveConstructor(JSContext *cx, JSObject *aObj,
1232 JSObject **objp)
1234 JS::Rooted<JSObject*> obj(cx, aObj);
1235 JS::Rooted<JSObject*> global(cx, ::JS_GetGlobalForObject(cx, obj));
1237 JS::Rooted<JS::Value> val(cx);
1238 if (!::JS_LookupProperty(cx, global, mData->mName, &val)) {
1239 return NS_ERROR_UNEXPECTED;
1242 if (!val.isPrimitive()) {
1243 // If val is not an (non-null) object there either is no
1244 // constructor for this class, or someone messed with
1245 // window.classname, just fall through and let the JS engine
1246 // return the Object constructor.
1248 JS::Rooted<jsid> id(cx, sConstructor_id);
1249 if (!::JS_DefinePropertyById(cx, obj, id, val, JSPROP_ENUMERATE,
1250 JS_PropertyStub, JS_StrictPropertyStub)) {
1251 return NS_ERROR_UNEXPECTED;
1254 *objp = obj;
1257 return NS_OK;
1260 NS_IMETHODIMP
1261 nsDOMClassInfo::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
1262 JSObject *obj, jsid id, JSObject **objp,
1263 bool *_retval)
1265 if (id == sConstructor_id) {
1266 return ResolveConstructor(cx, obj, objp);
1269 return NS_OK;
1272 NS_IMETHODIMP
1273 nsDOMClassInfo::Convert(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
1274 JSObject *obj, uint32_t type, jsval *vp,
1275 bool *_retval)
1277 NS_WARNING("nsDOMClassInfo::Convert Don't call me!");
1279 return NS_ERROR_UNEXPECTED;
1282 NS_IMETHODIMP
1283 nsDOMClassInfo::Finalize(nsIXPConnectWrappedNative *wrapper, JSFreeOp *fop,
1284 JSObject *obj)
1286 NS_WARNING("nsDOMClassInfo::Finalize Don't call me!");
1288 return NS_ERROR_UNEXPECTED;
1291 NS_IMETHODIMP
1292 nsDOMClassInfo::Call(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
1293 JSObject *obj, const JS::CallArgs &args, bool *_retval)
1295 NS_WARNING("nsDOMClassInfo::Call Don't call me!");
1297 return NS_ERROR_UNEXPECTED;
1300 NS_IMETHODIMP
1301 nsDOMClassInfo::Construct(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
1302 JSObject *obj, const JS::CallArgs &args,
1303 bool *_retval)
1305 NS_WARNING("nsDOMClassInfo::Construct Don't call me!");
1307 return NS_ERROR_UNEXPECTED;
1310 NS_IMETHODIMP
1311 nsDOMClassInfo::HasInstance(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
1312 JSObject *obj, JS::Handle<JS::Value> val, bool *bp,
1313 bool *_retval)
1315 NS_WARNING("nsDOMClassInfo::HasInstance Don't call me!");
1317 return NS_ERROR_UNEXPECTED;
1320 NS_IMETHODIMP
1321 nsDOMClassInfo::OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
1322 JSObject * obj, JSObject * *_retval)
1324 NS_WARNING("nsDOMClassInfo::OuterObject Don't call me!");
1326 return NS_ERROR_UNEXPECTED;
1329 static nsresult
1330 GetExternalClassInfo(nsScriptNameSpaceManager *aNameSpaceManager,
1331 const nsAString &aName,
1332 const nsGlobalNameStruct *aStruct,
1333 const nsGlobalNameStruct **aResult)
1335 NS_ASSERTION(aStruct->mType ==
1336 nsGlobalNameStruct::eTypeExternalClassInfoCreator,
1337 "Wrong type!");
1339 nsresult rv;
1340 nsCOMPtr<nsIDOMCIExtension> creator(do_CreateInstance(aStruct->mCID, &rv));
1341 NS_ENSURE_SUCCESS(rv, rv);
1343 nsCOMPtr<nsIDOMScriptObjectFactory> sof(do_GetService(kDOMSOF_CID));
1344 NS_ENSURE_TRUE(sof, NS_ERROR_FAILURE);
1346 rv = creator->RegisterDOMCI(NS_ConvertUTF16toUTF8(aName).get(), sof);
1347 NS_ENSURE_SUCCESS(rv, rv);
1349 const nsGlobalNameStruct *name_struct = aNameSpaceManager->LookupName(aName);
1350 if (name_struct &&
1351 name_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfo) {
1352 *aResult = name_struct;
1354 else {
1355 NS_ERROR("Couldn't get the DOM ClassInfo data.");
1357 *aResult = nullptr;
1360 return NS_OK;
1364 static nsresult
1365 ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx,
1366 JS::Handle<JSObject*> obj, const char16_t *name,
1367 const nsDOMClassInfoData *ci_data,
1368 const nsGlobalNameStruct *name_struct,
1369 nsScriptNameSpaceManager *nameSpaceManager,
1370 JSObject *dot_prototype,
1371 JS::MutableHandle<JSPropertyDescriptor> ctorDesc);
1373 NS_IMETHODIMP
1374 nsDOMClassInfo::PostCreatePrototype(JSContext * cx, JSObject * aProto)
1376 uint32_t flags = (mData->mScriptableFlags & DONT_ENUM_STATIC_PROPS)
1378 : JSPROP_ENUMERATE;
1380 uint32_t count = 0;
1381 while (mData->mInterfaces[count]) {
1382 count++;
1385 JS::Rooted<JSObject*> proto(cx, aProto);
1386 if (!xpc::DOM_DefineQuickStubs(cx, proto, flags, count, mData->mInterfaces)) {
1387 JS_ClearPendingException(cx);
1390 // This is called before any other location that requires
1391 // sObjectClass, so compute it here. We assume that nobody has had a
1392 // chance to monkey around with proto's prototype chain before this.
1393 if (!sObjectClass) {
1394 FindObjectClass(cx, proto);
1395 NS_ASSERTION(sObjectClass && !strcmp(sObjectClass->name, "Object"),
1396 "Incorrect object class!");
1399 #ifdef DEBUG
1400 JS::Rooted<JSObject*> proto2(cx);
1401 JS_GetPrototype(cx, proto, &proto2);
1402 NS_ASSERTION(proto2 && JS_GetClass(proto2) == sObjectClass,
1403 "Hmm, somebody did something evil?");
1404 #endif
1406 #ifdef DEBUG
1407 if (mData->mHasClassInterface && mData->mProtoChainInterface &&
1408 mData->mProtoChainInterface != &NS_GET_IID(nsISupports)) {
1409 nsCOMPtr<nsIInterfaceInfoManager>
1410 iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
1412 if (iim) {
1413 nsCOMPtr<nsIInterfaceInfo> if_info;
1414 iim->GetInfoForIID(mData->mProtoChainInterface,
1415 getter_AddRefs(if_info));
1417 if (if_info) {
1418 nsXPIDLCString name;
1419 if_info->GetName(getter_Copies(name));
1420 NS_ASSERTION(nsCRT::strcmp(CutPrefix(name), mData->mName) == 0,
1421 "Class name and proto chain interface name mismatch!");
1425 #endif
1427 // Make prototype delegation work correctly. Consider if a site sets
1428 // HTMLElement.prototype.foopy = function () { ... } Now, calling
1429 // document.body.foopy() needs to ensure that looking up foopy on
1430 // document.body's prototype will find the right function.
1431 JS::Rooted<JSObject*> global(cx, ::JS_GetGlobalForObject(cx, proto));
1433 // Only do this if the global object is a window.
1434 // XXX Is there a better way to check this?
1435 nsISupports *globalNative = XPConnect()->GetNativeOfWrapper(cx, global);
1436 nsCOMPtr<nsPIDOMWindow> piwin = do_QueryInterface(globalNative);
1437 if (!piwin) {
1438 return NS_OK;
1441 nsGlobalWindow *win = nsGlobalWindow::FromSupports(globalNative);
1442 if (win->IsClosedOrClosing()) {
1443 return NS_OK;
1446 // If the window is in a different compartment than the global object, then
1447 // it's likely that global is a sandbox object whose prototype is a window.
1448 // Don't do anything in this case.
1449 if (win->FastGetGlobalJSObject() &&
1450 js::GetObjectCompartment(global) != js::GetObjectCompartment(win->FastGetGlobalJSObject())) {
1451 return NS_OK;
1454 if (win->IsOuterWindow()) {
1455 // XXXjst: Do security checks here when we remove the security
1456 // checks on the inner window.
1458 win = win->GetCurrentInnerWindowInternal();
1460 if (!win || !(global = win->GetGlobalJSObject()) ||
1461 win->IsClosedOrClosing()) {
1462 return NS_OK;
1466 // Don't overwrite a property set by content.
1467 bool contentDefinedProperty;
1468 if (!::JS_AlreadyHasOwnUCProperty(cx, global, reinterpret_cast<const jschar*>(mData->mNameUTF16),
1469 NS_strlen(mData->mNameUTF16),
1470 &contentDefinedProperty)) {
1471 return NS_ERROR_FAILURE;
1474 nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
1475 NS_ENSURE_TRUE(nameSpaceManager, NS_OK);
1477 JS::Rooted<JSPropertyDescriptor> desc(cx);
1478 nsresult rv = ResolvePrototype(sXPConnect, win, cx, global, mData->mNameUTF16,
1479 mData, nullptr, nameSpaceManager, proto,
1480 &desc);
1481 NS_ENSURE_SUCCESS(rv, rv);
1482 if (!contentDefinedProperty && desc.object() && !desc.value().isUndefined() &&
1483 !JS_DefineUCProperty(cx, global, mData->mNameUTF16,
1484 NS_strlen(mData->mNameUTF16),
1485 desc.value(), desc.attributes(),
1486 desc.getter(), desc.setter())) {
1487 return NS_ERROR_UNEXPECTED;
1490 return NS_OK;
1493 // static
1494 nsIClassInfo *
1495 NS_GetDOMClassInfoInstance(nsDOMClassInfoID aID)
1497 if (aID >= eDOMClassInfoIDCount) {
1498 NS_ERROR("Bad ID!");
1500 return nullptr;
1503 nsresult rv = RegisterDOMNames();
1504 NS_ENSURE_SUCCESS(rv, nullptr);
1506 if (!sClassInfoData[aID].mCachedClassInfo) {
1507 nsDOMClassInfoData& data = sClassInfoData[aID];
1509 data.mCachedClassInfo = data.u.mConstructorFptr(&data);
1510 NS_ENSURE_TRUE(data.mCachedClassInfo, nullptr);
1512 NS_ADDREF(data.mCachedClassInfo);
1515 NS_ASSERTION(!IS_EXTERNAL(sClassInfoData[aID].mCachedClassInfo),
1516 "This is bad, internal class marked as external!");
1518 return sClassInfoData[aID].mCachedClassInfo;
1521 // static
1522 nsIClassInfo *
1523 nsDOMClassInfo::GetClassInfoInstance(nsDOMClassInfoData* aData)
1525 NS_ASSERTION(IS_EXTERNAL(aData->mCachedClassInfo)
1526 || !aData->mCachedClassInfo,
1527 "This is bad, external class marked as internal!");
1529 if (!aData->mCachedClassInfo) {
1530 if (aData->u.mExternalConstructorFptr) {
1531 aData->mCachedClassInfo =
1532 aData->u.mExternalConstructorFptr(aData->mName);
1533 } else {
1534 aData->mCachedClassInfo = nsDOMGenericSH::doCreate(aData);
1536 NS_ENSURE_TRUE(aData->mCachedClassInfo, nullptr);
1538 NS_ADDREF(aData->mCachedClassInfo);
1539 aData->mCachedClassInfo = MARK_EXTERNAL(aData->mCachedClassInfo);
1542 return GET_CLEAN_CI_PTR(aData->mCachedClassInfo);
1546 // static
1547 void
1548 nsDOMClassInfo::ShutDown()
1550 if (sClassInfoData[0].u.mConstructorFptr) {
1551 uint32_t i;
1553 for (i = 0; i < eDOMClassInfoIDCount; i++) {
1554 NS_IF_RELEASE(sClassInfoData[i].mCachedClassInfo);
1558 sLocation_id = JSID_VOID;
1559 sConstructor_id = JSID_VOID;
1560 sTop_id = JSID_VOID;
1561 sDocument_id = JSID_VOID;
1562 sWrappedJSObject_id = JSID_VOID;
1564 NS_IF_RELEASE(sXPConnect);
1565 sIsInitialized = false;
1568 // Window helper
1570 NS_IMETHODIMP
1571 nsWindowSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
1572 JSObject *globalObj, JSObject **parentObj)
1574 // Normally ::PreCreate() is used to give XPConnect the parent
1575 // object for the object that's being wrapped, this parent object is
1576 // set as the parent of the wrapper and it's also used to find the
1577 // right scope for the object being wrapped. Now, in the case of the
1578 // global object the wrapper shouldn't have a parent but we supply
1579 // one here anyway (the global object itself) and this will be used
1580 // by XPConnect only to find the right scope, once the scope is
1581 // found XPConnect will find the existing wrapper (which always
1582 // exists since it's created on window construction), since an
1583 // existing wrapper is found the parent we supply here is ignored
1584 // after the wrapper is found.
1586 nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(nativeObj));
1587 NS_ASSERTION(sgo, "nativeObj not a global object!");
1589 nsGlobalWindow *win = nsGlobalWindow::FromSupports(nativeObj);
1590 NS_ASSERTION(win->IsInnerWindow(), "Should be inner window.");
1592 // We sometimes get a disconnected window during file api test. :-(
1593 if (!win->GetOuterWindowInternal())
1594 return NS_ERROR_FAILURE;
1596 // If we're bootstrapping, we don't have a JS object yet.
1597 if (win->GetOuterWindowInternal()->IsCreatingInnerWindow())
1598 return NS_OK;
1600 return SetParentToWindow(win, parentObj);
1603 NS_IMETHODIMP
1604 nsWindowSH::PostCreatePrototype(JSContext* aCx, JSObject* aProto)
1606 JS::Rooted<JSObject*> proto(aCx, aProto);
1608 nsresult rv = nsDOMClassInfo::PostCreatePrototype(aCx, proto);
1609 NS_ENSURE_SUCCESS(rv, rv);
1611 // We should probably move this into the CreateInterfaceObjects for Window
1612 // once it is on WebIDL bindings.
1613 WindowNamedPropertiesHandler::Install(aCx, proto);
1614 return NS_OK;
1617 NS_IMETHODIMP
1618 nsWindowSH::PostCreate(nsIXPConnectWrappedNative *wrapper,
1619 JSContext *cx, JSObject *obj)
1621 JS::Rooted<JSObject*> window(cx, obj);
1623 #ifdef DEBUG
1624 nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryWrappedNative(wrapper));
1626 NS_ASSERTION(sgo && sgo->GetGlobalJSObject() == obj,
1627 "Multiple wrappers created for global object!");
1628 #endif
1630 const NativeProperties* windowProperties =
1631 WindowBinding::sNativePropertyHooks->mNativeProperties.regular;
1632 const NativeProperties* eventTargetProperties =
1633 EventTargetBinding::sNativePropertyHooks->mNativeProperties.regular;
1635 if (!DefineWebIDLBindingUnforgeablePropertiesOnXPCObject(cx, window, windowProperties) ||
1636 !DefineWebIDLBindingUnforgeablePropertiesOnXPCObject(cx, window, eventTargetProperties)) {
1637 return NS_ERROR_FAILURE;
1640 if (!GlobalPropertiesAreOwn()) {
1641 return NS_OK;
1644 return DefineWebIDLBindingPropertiesOnXPCObject(cx, window, windowProperties) &&
1645 DefineWebIDLBindingPropertiesOnXPCObject(cx, window, eventTargetProperties) ?
1646 NS_OK : NS_ERROR_FAILURE;
1649 struct ResolveGlobalNameClosure
1651 JSContext* cx;
1652 JS::Handle<JSObject*> obj;
1653 bool* retval;
1656 static PLDHashOperator
1657 ResolveGlobalName(const nsAString& aName,
1658 const nsGlobalNameStruct& aNameStruct,
1659 void* aClosure)
1661 ResolveGlobalNameClosure* closure =
1662 static_cast<ResolveGlobalNameClosure*>(aClosure);
1663 JS::Rooted<JS::Value> dummy(closure->cx);
1664 bool ok = JS_LookupUCProperty(closure->cx, closure->obj,
1665 aName.BeginReading(), aName.Length(),
1666 &dummy);
1667 if (!ok) {
1668 *closure->retval = false;
1669 return PL_DHASH_STOP;
1671 return PL_DHASH_NEXT;
1674 NS_IMETHODIMP
1675 nsWindowSH::Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
1676 JSObject *aObj, bool *_retval)
1678 JS::Rooted<JSObject*> obj(cx, aObj);
1679 if (!xpc::WrapperFactory::IsXrayWrapper(obj)) {
1680 *_retval = JS_EnumerateStandardClasses(cx, obj);
1681 if (!*_retval) {
1682 return NS_OK;
1685 // Now resolve everything from the namespace manager
1686 nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
1687 if (!nameSpaceManager) {
1688 NS_ERROR("Can't get namespace manager.");
1689 return NS_ERROR_UNEXPECTED;
1691 ResolveGlobalNameClosure closure = { cx, obj, _retval };
1692 nameSpaceManager->EnumerateGlobalNames(ResolveGlobalName, &closure);
1695 return NS_OK;
1698 static nsDOMConstructorFunc
1699 FindConstructorFunc(const nsDOMClassInfoData *aDOMClassInfoData)
1701 for (uint32_t i = 0; i < ArrayLength(kConstructorFuncMap); ++i) {
1702 if (&sClassInfoData[kConstructorFuncMap[i].mDOMClassInfoID] ==
1703 aDOMClassInfoData) {
1704 return kConstructorFuncMap[i].mConstructorFunc;
1707 return nullptr;
1710 static nsresult
1711 BaseStubConstructor(nsIWeakReference* aWeakOwner,
1712 const nsGlobalNameStruct *name_struct, JSContext *cx,
1713 JS::Handle<JSObject*> obj, const JS::CallArgs &args)
1715 MOZ_ASSERT(obj);
1716 MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
1718 nsresult rv;
1719 nsCOMPtr<nsISupports> native;
1720 if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
1721 const nsDOMClassInfoData* ci_data =
1722 &sClassInfoData[name_struct->mDOMClassInfoID];
1723 nsDOMConstructorFunc func = FindConstructorFunc(ci_data);
1724 if (func) {
1725 rv = func(getter_AddRefs(native));
1726 } else {
1727 rv = NS_ERROR_NOT_AVAILABLE;
1729 } else if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructor) {
1730 native = do_CreateInstance(name_struct->mCID, &rv);
1731 } else if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias) {
1732 native = do_CreateInstance(name_struct->mAlias->mCID, &rv);
1733 } else {
1734 native = do_CreateInstance(*name_struct->mData->mConstructorCID, &rv);
1736 if (NS_FAILED(rv)) {
1737 NS_ERROR("Failed to create the object");
1738 return rv;
1741 nsCOMPtr<nsIJSNativeInitializer> initializer(do_QueryInterface(native));
1742 nsCOMPtr<nsIDOMGlobalObjectConstructor> constructor(do_QueryInterface(native));
1743 if (initializer || constructor) {
1744 // Initialize object using the current inner window, but only if
1745 // the caller can access it.
1746 nsCOMPtr<nsPIDOMWindow> owner = do_QueryReferent(aWeakOwner);
1747 nsPIDOMWindow* outerWindow = owner ? owner->GetOuterWindow() : nullptr;
1748 nsPIDOMWindow* currentInner =
1749 outerWindow ? outerWindow->GetCurrentInnerWindow() : nullptr;
1750 if (!currentInner ||
1751 (owner != currentInner &&
1752 !nsContentUtils::CanCallerAccess(currentInner))) {
1753 return NS_ERROR_DOM_SECURITY_ERR;
1756 if (initializer) {
1757 rv = initializer->Initialize(currentInner, cx, obj, args);
1758 if (NS_FAILED(rv)) {
1759 return rv;
1761 } else {
1762 nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS = do_QueryInterface(native);
1764 JS::Rooted<JSObject*> thisObject(cx, wrappedJS->GetJSObject());
1765 if (!thisObject) {
1766 return NS_ERROR_UNEXPECTED;
1769 JSAutoCompartment ac(cx, thisObject);
1771 JS::Rooted<JS::Value> funval(cx);
1772 if (!JS_GetProperty(cx, thisObject, "constructor", &funval) ||
1773 !funval.isObject()) {
1774 return NS_ERROR_UNEXPECTED;
1777 // Check if the object is even callable.
1778 NS_ENSURE_STATE(JS_ObjectIsCallable(cx, &funval.toObject()));
1780 // wrap parameters in the target compartment
1781 // we also pass in the calling window as the first argument
1782 unsigned argc = args.length() + 1;
1783 JS::AutoValueVector argv(cx);
1784 if (!argv.resize(argc)) {
1785 return NS_ERROR_OUT_OF_MEMORY;
1788 nsCOMPtr<nsIDOMWindow> currentWin(do_GetInterface(currentInner));
1789 rv = WrapNative(cx, currentWin, &NS_GET_IID(nsIDOMWindow),
1790 true, argv[0]);
1792 for (size_t i = 1; i < argc; ++i) {
1793 argv[i].set(args[i - 1]);
1794 if (!JS_WrapValue(cx, argv[i]))
1795 return NS_ERROR_FAILURE;
1798 JS::Rooted<JS::Value> frval(cx);
1799 bool ret = JS_CallFunctionValue(cx, thisObject, funval, argv, &frval);
1801 if (!ret) {
1802 return NS_ERROR_FAILURE;
1808 js::AssertSameCompartment(cx, obj);
1809 return WrapNative(cx, native, true, args.rval());
1812 static nsresult
1813 DefineInterfaceConstants(JSContext *cx, JS::Handle<JSObject*> obj, const nsIID *aIID)
1815 nsCOMPtr<nsIInterfaceInfoManager>
1816 iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
1817 NS_ENSURE_TRUE(iim, NS_ERROR_UNEXPECTED);
1819 nsCOMPtr<nsIInterfaceInfo> if_info;
1821 nsresult rv = iim->GetInfoForIID(aIID, getter_AddRefs(if_info));
1822 NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && if_info, rv);
1824 uint16_t constant_count;
1826 if_info->GetConstantCount(&constant_count);
1828 if (!constant_count) {
1829 return NS_OK;
1832 nsCOMPtr<nsIInterfaceInfo> parent_if_info;
1834 rv = if_info->GetParent(getter_AddRefs(parent_if_info));
1835 NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && parent_if_info, rv);
1837 uint16_t parent_constant_count, i;
1838 parent_if_info->GetConstantCount(&parent_constant_count);
1840 JS::Rooted<JS::Value> v(cx);
1841 for (i = parent_constant_count; i < constant_count; i++) {
1842 nsXPIDLCString name;
1843 rv = if_info->GetConstant(i, &v, getter_Copies(name));
1844 NS_ENSURE_TRUE(NS_SUCCEEDED(rv), rv);
1846 if (!::JS_DefineProperty(cx, obj, name, v,
1847 JSPROP_ENUMERATE | JSPROP_READONLY |
1848 JSPROP_PERMANENT,
1849 JS_PropertyStub, JS_StrictPropertyStub)) {
1850 return NS_ERROR_UNEXPECTED;
1854 return NS_OK;
1857 class nsDOMConstructor MOZ_FINAL : public nsIDOMDOMConstructor
1859 protected:
1860 nsDOMConstructor(const char16_t* aName,
1861 bool aIsConstructable,
1862 nsPIDOMWindow* aOwner)
1863 : mClassName(aName),
1864 mConstructable(aIsConstructable),
1865 mWeakOwner(do_GetWeakReference(aOwner))
1869 ~nsDOMConstructor() {}
1871 public:
1873 static nsresult Create(const char16_t* aName,
1874 const nsDOMClassInfoData* aData,
1875 const nsGlobalNameStruct* aNameStruct,
1876 nsPIDOMWindow* aOwner,
1877 nsDOMConstructor** aResult);
1879 NS_DECL_ISUPPORTS
1880 NS_DECL_NSIDOMDOMCONSTRUCTOR
1882 nsresult PreCreate(JSContext *cx, JSObject *globalObj, JSObject **parentObj);
1884 nsresult Construct(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
1885 JS::Handle<JSObject*> obj, const JS::CallArgs &args,
1886 bool *_retval);
1888 nsresult HasInstance(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
1889 JS::Handle<JSObject*> obj, const jsval &val, bool *bp,
1890 bool *_retval);
1892 nsresult ResolveInterfaceConstants(JSContext *cx, JS::Handle<JSObject*> obj);
1894 private:
1895 const nsGlobalNameStruct *GetNameStruct()
1897 if (!mClassName) {
1898 NS_ERROR("Can't get name");
1899 return nullptr;
1902 const nsGlobalNameStruct *nameStruct;
1903 #ifdef DEBUG
1904 nsresult rv =
1905 #endif
1906 GetNameStruct(nsDependentString(mClassName), &nameStruct);
1908 NS_ASSERTION(NS_FAILED(rv) || nameStruct, "Name isn't in hash.");
1910 return nameStruct;
1913 static nsresult GetNameStruct(const nsAString& aName,
1914 const nsGlobalNameStruct **aNameStruct)
1916 *aNameStruct = nullptr;
1918 nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
1919 if (!nameSpaceManager) {
1920 NS_ERROR("Can't get namespace manager.");
1921 return NS_ERROR_UNEXPECTED;
1924 *aNameStruct = nameSpaceManager->LookupName(aName);
1926 // Return NS_OK here, aName just isn't a DOM class but nothing failed.
1927 return NS_OK;
1930 static bool IsConstructable(const nsDOMClassInfoData *aData)
1932 if (IS_EXTERNAL(aData->mCachedClassInfo)) {
1933 const nsExternalDOMClassInfoData* data =
1934 static_cast<const nsExternalDOMClassInfoData*>(aData);
1935 return data->mConstructorCID != nullptr;
1938 return FindConstructorFunc(aData);
1940 static bool IsConstructable(const nsGlobalNameStruct *aNameStruct)
1942 return
1943 (aNameStruct->mType == nsGlobalNameStruct::eTypeClassConstructor &&
1944 IsConstructable(&sClassInfoData[aNameStruct->mDOMClassInfoID])) ||
1945 (aNameStruct->mType == nsGlobalNameStruct::eTypeExternalClassInfo &&
1946 IsConstructable(aNameStruct->mData)) ||
1947 aNameStruct->mType == nsGlobalNameStruct::eTypeExternalConstructor ||
1948 aNameStruct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias;
1951 const char16_t* mClassName;
1952 const bool mConstructable;
1953 nsWeakPtr mWeakOwner;
1956 //static
1957 nsresult
1958 nsDOMConstructor::Create(const char16_t* aName,
1959 const nsDOMClassInfoData* aData,
1960 const nsGlobalNameStruct* aNameStruct,
1961 nsPIDOMWindow* aOwner,
1962 nsDOMConstructor** aResult)
1964 *aResult = nullptr;
1965 // Prevent creating a constructor if aOwner is inner window which doesn't have
1966 // an outer window. If the outer window doesn't have an inner window or the
1967 // caller can't access the outer window's current inner window then try to use
1968 // the owner (so long as it is, in fact, an inner window). If that doesn't
1969 // work then prevent creation also.
1970 nsPIDOMWindow* outerWindow = aOwner->GetOuterWindow();
1971 nsPIDOMWindow* currentInner =
1972 outerWindow ? outerWindow->GetCurrentInnerWindow() : aOwner;
1973 if (!currentInner ||
1974 (aOwner != currentInner &&
1975 !nsContentUtils::CanCallerAccess(currentInner) &&
1976 !(currentInner = aOwner)->IsInnerWindow())) {
1977 return NS_ERROR_DOM_SECURITY_ERR;
1980 bool constructable = aNameStruct ?
1981 IsConstructable(aNameStruct) :
1982 IsConstructable(aData);
1984 *aResult = new nsDOMConstructor(aName, constructable, currentInner);
1985 NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
1986 NS_ADDREF(*aResult);
1987 return NS_OK;
1990 NS_IMPL_ADDREF(nsDOMConstructor)
1991 NS_IMPL_RELEASE(nsDOMConstructor)
1992 NS_INTERFACE_MAP_BEGIN(nsDOMConstructor)
1993 NS_INTERFACE_MAP_ENTRY(nsIDOMDOMConstructor)
1994 NS_INTERFACE_MAP_ENTRY(nsISupports)
1995 if (aIID.Equals(NS_GET_IID(nsIClassInfo))) {
1996 #ifdef DEBUG
1998 const nsGlobalNameStruct *name_struct = GetNameStruct();
1999 NS_ASSERTION(!name_struct ||
2000 mConstructable == IsConstructable(name_struct),
2001 "Can't change constructability dynamically!");
2003 #endif
2004 foundInterface =
2005 NS_GetDOMClassInfoInstance(mConstructable ?
2006 eDOMClassInfo_DOMConstructor_id :
2007 eDOMClassInfo_DOMPrototype_id);
2008 if (!foundInterface) {
2009 *aInstancePtr = nullptr;
2010 return NS_ERROR_OUT_OF_MEMORY;
2012 } else
2013 NS_INTERFACE_MAP_END
2015 nsresult
2016 nsDOMConstructor::PreCreate(JSContext *cx, JSObject *globalObj, JSObject **parentObj)
2018 nsCOMPtr<nsPIDOMWindow> owner(do_QueryReferent(mWeakOwner));
2019 if (!owner) {
2020 // Can't do anything.
2021 return NS_OK;
2024 nsGlobalWindow *win = static_cast<nsGlobalWindow *>(owner.get());
2025 return SetParentToWindow(win, parentObj);
2028 nsresult
2029 nsDOMConstructor::Construct(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
2030 JS::Handle<JSObject*> obj, const JS::CallArgs &args,
2031 bool *_retval)
2033 MOZ_ASSERT(obj);
2035 const nsGlobalNameStruct *name_struct = GetNameStruct();
2036 NS_ENSURE_TRUE(name_struct, NS_ERROR_FAILURE);
2038 if (!IsConstructable(name_struct)) {
2039 // ignore return value, we return false anyway
2040 return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
2043 return BaseStubConstructor(mWeakOwner, name_struct, cx, obj, args);
2046 nsresult
2047 nsDOMConstructor::HasInstance(nsIXPConnectWrappedNative *wrapper,
2048 JSContext * cx, JS::Handle<JSObject*> obj,
2049 const jsval &v, bool *bp, bool *_retval)
2052 // No need to look these up in the hash.
2053 *bp = false;
2054 if (v.isPrimitive()) {
2055 return NS_OK;
2058 JS::Rooted<JSObject*> dom_obj(cx, v.toObjectOrNull());
2059 NS_ASSERTION(dom_obj, "nsDOMConstructor::HasInstance couldn't get object");
2061 // This might not be the right object, if there are wrappers. Unwrap if we can.
2062 JSObject *wrapped_obj = js::CheckedUnwrap(dom_obj, /* stopAtOuter = */ false);
2063 if (wrapped_obj)
2064 dom_obj = wrapped_obj;
2066 const JSClass *dom_class = JS_GetClass(dom_obj);
2067 if (!dom_class) {
2068 NS_ERROR("nsDOMConstructor::HasInstance can't get class.");
2069 return NS_ERROR_UNEXPECTED;
2072 const nsGlobalNameStruct *name_struct;
2073 nsresult rv = GetNameStruct(NS_ConvertASCIItoUTF16(dom_class->name), &name_struct);
2074 if (NS_FAILED(rv)) {
2075 return rv;
2078 if (!name_struct) {
2079 // This isn't a normal DOM object, see if this constructor lives on its
2080 // prototype chain.
2081 JS::Rooted<JS::Value> val(cx);
2082 if (!JS_GetProperty(cx, obj, "prototype", &val)) {
2083 return NS_ERROR_UNEXPECTED;
2086 if (val.isPrimitive()) {
2087 return NS_OK;
2090 JS::Rooted<JSObject*> dot_prototype(cx, val.toObjectOrNull());
2092 JS::Rooted<JSObject*> proto(cx, dom_obj);
2093 for (;;) {
2094 if (!JS_GetPrototype(cx, proto, &proto)) {
2095 return NS_ERROR_UNEXPECTED;
2097 if (!proto) {
2098 break;
2100 if (proto == dot_prototype) {
2101 *bp = true;
2102 break;
2106 return NS_OK;
2109 if (name_struct->mType != nsGlobalNameStruct::eTypeClassConstructor &&
2110 name_struct->mType != nsGlobalNameStruct::eTypeExternalClassInfo &&
2111 name_struct->mType != nsGlobalNameStruct::eTypeExternalConstructorAlias) {
2112 // Doesn't have DOM interfaces.
2113 return NS_OK;
2116 const nsGlobalNameStruct *class_name_struct = GetNameStruct();
2117 NS_ENSURE_TRUE(class_name_struct, NS_ERROR_FAILURE);
2119 if (name_struct == class_name_struct) {
2120 *bp = true;
2122 return NS_OK;
2125 nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
2126 NS_ASSERTION(nameSpaceManager, "Can't get namespace manager?");
2128 const nsIID *class_iid;
2129 if (class_name_struct->mType == nsGlobalNameStruct::eTypeInterface ||
2130 class_name_struct->mType == nsGlobalNameStruct::eTypeClassProto) {
2131 class_iid = &class_name_struct->mIID;
2132 } else if (class_name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
2133 class_iid =
2134 sClassInfoData[class_name_struct->mDOMClassInfoID].mProtoChainInterface;
2135 } else if (class_name_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfo) {
2136 class_iid = class_name_struct->mData->mProtoChainInterface;
2137 } else if (class_name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias) {
2138 const nsGlobalNameStruct* alias_struct =
2139 nameSpaceManager->GetConstructorProto(class_name_struct);
2140 if (!alias_struct) {
2141 NS_ERROR("Couldn't get constructor prototype.");
2142 return NS_ERROR_UNEXPECTED;
2145 if (alias_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
2146 class_iid =
2147 sClassInfoData[alias_struct->mDOMClassInfoID].mProtoChainInterface;
2148 } else if (alias_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfo) {
2149 class_iid = alias_struct->mData->mProtoChainInterface;
2150 } else {
2151 NS_ERROR("Expected eTypeClassConstructor or eTypeExternalClassInfo.");
2152 return NS_ERROR_UNEXPECTED;
2154 } else {
2155 *bp = false;
2157 return NS_OK;
2160 if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias) {
2161 name_struct = nameSpaceManager->GetConstructorProto(name_struct);
2162 if (!name_struct) {
2163 NS_ERROR("Couldn't get constructor prototype.");
2164 return NS_ERROR_UNEXPECTED;
2168 NS_ASSERTION(name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor ||
2169 name_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfo,
2170 "The constructor was set up with a struct of the wrong type.");
2172 const nsDOMClassInfoData *ci_data = nullptr;
2173 if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor &&
2174 name_struct->mDOMClassInfoID >= 0) {
2175 ci_data = &sClassInfoData[name_struct->mDOMClassInfoID];
2176 } else if (name_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfo) {
2177 ci_data = name_struct->mData;
2180 nsCOMPtr<nsIInterfaceInfoManager>
2181 iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
2182 if (!iim) {
2183 NS_ERROR("nsDOMConstructor::HasInstance can't get interface info mgr.");
2184 return NS_ERROR_UNEXPECTED;
2187 nsCOMPtr<nsIInterfaceInfo> if_info;
2188 uint32_t count = 0;
2189 const nsIID* class_interface;
2190 while ((class_interface = ci_data->mInterfaces[count++])) {
2191 if (class_iid->Equals(*class_interface)) {
2192 *bp = true;
2194 return NS_OK;
2197 iim->GetInfoForIID(class_interface, getter_AddRefs(if_info));
2198 if (!if_info) {
2199 NS_ERROR("nsDOMConstructor::HasInstance can't get interface info.");
2200 return NS_ERROR_UNEXPECTED;
2203 if_info->HasAncestor(class_iid, bp);
2205 if (*bp) {
2206 return NS_OK;
2210 return NS_OK;
2213 nsresult
2214 nsDOMConstructor::ResolveInterfaceConstants(JSContext *cx, JS::Handle<JSObject*> obj)
2216 const nsGlobalNameStruct *class_name_struct = GetNameStruct();
2217 if (!class_name_struct)
2218 return NS_ERROR_UNEXPECTED;
2220 const nsIID *class_iid;
2221 if (class_name_struct->mType == nsGlobalNameStruct::eTypeInterface ||
2222 class_name_struct->mType == nsGlobalNameStruct::eTypeClassProto) {
2223 class_iid = &class_name_struct->mIID;
2224 } else if (class_name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
2225 class_iid =
2226 sClassInfoData[class_name_struct->mDOMClassInfoID].mProtoChainInterface;
2227 } else if (class_name_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfo) {
2228 class_iid = class_name_struct->mData->mProtoChainInterface;
2229 } else {
2230 return NS_OK;
2233 nsresult rv = DefineInterfaceConstants(cx, obj, class_iid);
2234 NS_ENSURE_SUCCESS(rv, rv);
2236 return NS_OK;
2239 NS_IMETHODIMP
2240 nsDOMConstructor::ToString(nsAString &aResult)
2242 aResult.AssignLiteral("[object ");
2243 aResult.Append(mClassName);
2244 aResult.Append(char16_t(']'));
2246 return NS_OK;
2250 static nsresult
2251 GetXPCProto(nsIXPConnect *aXPConnect, JSContext *cx, nsGlobalWindow *aWin,
2252 const nsGlobalNameStruct *aNameStruct,
2253 nsIXPConnectJSObjectHolder **aProto)
2255 NS_ASSERTION(aNameStruct->mType ==
2256 nsGlobalNameStruct::eTypeClassConstructor ||
2257 aNameStruct->mType == nsGlobalNameStruct::eTypeExternalClassInfo,
2258 "Wrong type!");
2260 nsCOMPtr<nsIClassInfo> ci;
2261 if (aNameStruct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
2262 int32_t id = aNameStruct->mDOMClassInfoID;
2263 NS_ABORT_IF_FALSE(id >= 0, "Negative DOM classinfo?!?");
2265 nsDOMClassInfoID ci_id = (nsDOMClassInfoID)id;
2267 ci = NS_GetDOMClassInfoInstance(ci_id);
2269 // In most cases we want to find the wrapped native prototype in
2270 // aWin's scope and use that prototype for
2271 // ClassName.prototype. But in the case where we're setting up
2272 // "Window.prototype" or "ChromeWindow.prototype" we want to do
2273 // the look up in aWin's outer window's scope since the inner
2274 // window's wrapped native prototype comes from the outer
2275 // window's scope.
2276 if (ci_id == eDOMClassInfo_Window_id ||
2277 ci_id == eDOMClassInfo_ModalContentWindow_id ||
2278 ci_id == eDOMClassInfo_ChromeWindow_id) {
2279 nsGlobalWindow *scopeWindow = aWin->GetOuterWindowInternal();
2281 if (scopeWindow) {
2282 aWin = scopeWindow;
2286 else {
2287 ci = nsDOMClassInfo::GetClassInfoInstance(aNameStruct->mData);
2289 NS_ENSURE_TRUE(ci, NS_ERROR_UNEXPECTED);
2291 nsresult rv =
2292 aXPConnect->GetWrappedNativePrototype(cx, aWin->GetGlobalJSObject(), ci,
2293 aProto);
2294 NS_ENSURE_SUCCESS(rv, rv);
2296 JS::Rooted<JSObject*> proto_obj(cx, (*aProto)->GetJSObject());
2297 if (!JS_WrapObject(cx, &proto_obj)) {
2298 return NS_ERROR_FAILURE;
2301 NS_IF_RELEASE(*aProto);
2302 return aXPConnect->HoldObject(cx, proto_obj, aProto);
2305 // Either ci_data must be non-null or name_struct must be non-null and of type
2306 // eTypeClassProto.
2307 static nsresult
2308 ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx,
2309 JS::Handle<JSObject*> obj, const char16_t *name,
2310 const nsDOMClassInfoData *ci_data,
2311 const nsGlobalNameStruct *name_struct,
2312 nsScriptNameSpaceManager *nameSpaceManager,
2313 JSObject* aDot_prototype,
2314 JS::MutableHandle<JSPropertyDescriptor> ctorDesc)
2316 JS::Rooted<JSObject*> dot_prototype(cx, aDot_prototype);
2317 NS_ASSERTION(ci_data ||
2318 (name_struct &&
2319 name_struct->mType == nsGlobalNameStruct::eTypeClassProto),
2320 "Wrong type or missing ci_data!");
2322 nsRefPtr<nsDOMConstructor> constructor;
2323 nsresult rv = nsDOMConstructor::Create(name, ci_data, name_struct, aWin,
2324 getter_AddRefs(constructor));
2325 NS_ENSURE_SUCCESS(rv, rv);
2327 JS::Rooted<JS::Value> v(cx);
2329 js::AssertSameCompartment(cx, obj);
2330 rv = WrapNative(cx, constructor, &NS_GET_IID(nsIDOMDOMConstructor),
2331 false, &v);
2332 NS_ENSURE_SUCCESS(rv, rv);
2334 FillPropertyDescriptor(ctorDesc, obj, 0, v);
2335 // And make sure we wrap the value into the right compartment. Note that we
2336 // do this with ctorDesc.value(), not with v, because we need v to be in the
2337 // right compartment (that of the reflector of |constructor|) below.
2338 if (!JS_WrapValue(cx, ctorDesc.value())) {
2339 return NS_ERROR_UNEXPECTED;
2342 JS::Rooted<JSObject*> class_obj(cx, &v.toObject());
2344 const nsIID *primary_iid = &NS_GET_IID(nsISupports);
2346 if (!ci_data) {
2347 primary_iid = &name_struct->mIID;
2349 else if (ci_data->mProtoChainInterface) {
2350 primary_iid = ci_data->mProtoChainInterface;
2353 nsCOMPtr<nsIInterfaceInfo> if_info;
2354 nsCOMPtr<nsIInterfaceInfo> parent;
2355 const char *class_parent_name = nullptr;
2357 if (!primary_iid->Equals(NS_GET_IID(nsISupports))) {
2358 JSAutoCompartment ac(cx, class_obj);
2360 rv = DefineInterfaceConstants(cx, class_obj, primary_iid);
2361 NS_ENSURE_SUCCESS(rv, rv);
2363 nsCOMPtr<nsIInterfaceInfoManager>
2364 iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
2365 NS_ENSURE_TRUE(iim, NS_ERROR_NOT_AVAILABLE);
2367 iim->GetInfoForIID(primary_iid, getter_AddRefs(if_info));
2368 NS_ENSURE_TRUE(if_info, NS_ERROR_UNEXPECTED);
2370 const nsIID *iid = nullptr;
2372 if (ci_data && !ci_data->mHasClassInterface) {
2373 if_info->GetIIDShared(&iid);
2374 } else {
2375 if_info->GetParent(getter_AddRefs(parent));
2376 NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED);
2378 parent->GetIIDShared(&iid);
2381 if (iid) {
2382 if (!iid->Equals(NS_GET_IID(nsISupports))) {
2383 if (ci_data && !ci_data->mHasClassInterface) {
2384 // If the class doesn't have a class interface the primary
2385 // interface is the interface that should be
2386 // constructor.prototype.__proto__.
2388 if_info->GetNameShared(&class_parent_name);
2389 } else {
2390 // If the class does have a class interface (or there's no
2391 // real class for this name) then the parent of the
2392 // primary interface is what we want on
2393 // constructor.prototype.__proto__.
2395 NS_ASSERTION(parent, "Whoa, this is bad, null parent here!");
2397 parent->GetNameShared(&class_parent_name);
2404 JS::Rooted<JSObject*> winobj(cx, aWin->FastGetGlobalJSObject());
2406 JS::Rooted<JSObject*> proto(cx);
2408 if (class_parent_name) {
2409 JSAutoCompartment ac(cx, winobj);
2411 JS::Rooted<JS::Value> val(cx);
2412 if (!JS_LookupProperty(cx, winobj, CutPrefix(class_parent_name), &val)) {
2413 return NS_ERROR_UNEXPECTED;
2416 if (val.isObject()) {
2417 JS::Rooted<JSObject*> obj(cx, &val.toObject());
2418 if (!JS_LookupProperty(cx, obj, "prototype", &val)) {
2419 return NS_ERROR_UNEXPECTED;
2422 if (val.isObject()) {
2423 proto = &val.toObject();
2428 if (dot_prototype) {
2429 JSAutoCompartment ac(cx, dot_prototype);
2430 JS::Rooted<JSObject*> xpc_proto_proto(cx);
2431 if (!::JS_GetPrototype(cx, dot_prototype, &xpc_proto_proto)) {
2432 return NS_ERROR_UNEXPECTED;
2435 if (proto &&
2436 (!xpc_proto_proto ||
2437 JS_GetClass(xpc_proto_proto) == sObjectClass)) {
2438 if (!JS_WrapObject(cx, &proto) ||
2439 !JS_SetPrototype(cx, dot_prototype, proto)) {
2440 return NS_ERROR_UNEXPECTED;
2443 } else {
2444 JSAutoCompartment ac(cx, winobj);
2445 if (!proto) {
2446 proto = JS_GetObjectPrototype(cx, winobj);
2448 dot_prototype = ::JS_NewObjectWithUniqueType(cx,
2449 &sDOMConstructorProtoClass,
2450 proto,
2451 winobj);
2452 NS_ENSURE_TRUE(dot_prototype, NS_ERROR_OUT_OF_MEMORY);
2456 v = OBJECT_TO_JSVAL(dot_prototype);
2458 JSAutoCompartment ac(cx, class_obj);
2460 // Per ECMA, the prototype property is {DontEnum, DontDelete, ReadOnly}
2461 if (!JS_WrapValue(cx, &v) ||
2462 !JS_DefineProperty(cx, class_obj, "prototype", v,
2463 JSPROP_PERMANENT | JSPROP_READONLY,
2464 JS_PropertyStub, JS_StrictPropertyStub)) {
2465 return NS_ERROR_UNEXPECTED;
2468 return NS_OK;
2471 static bool
2472 OldBindingConstructorEnabled(const nsGlobalNameStruct *aStruct,
2473 nsGlobalWindow *aWin, JSContext *cx)
2475 MOZ_ASSERT(aStruct->mType == nsGlobalNameStruct::eTypeProperty ||
2476 aStruct->mType == nsGlobalNameStruct::eTypeClassConstructor ||
2477 aStruct->mType == nsGlobalNameStruct::eTypeExternalClassInfo);
2479 // Don't expose chrome only constructors to content windows.
2480 if (aStruct->mChromeOnly) {
2481 bool expose;
2482 if (aStruct->mAllowXBL) {
2483 expose = IsChromeOrXBL(cx, nullptr);
2484 } else {
2485 expose = nsContentUtils::IsSystemPrincipal(aWin->GetPrincipal());
2488 if (!expose) {
2489 return false;
2493 return true;
2496 static nsresult
2497 LookupComponentsShim(JSContext *cx, JS::Handle<JSObject*> global,
2498 nsPIDOMWindow *win,
2499 JS::MutableHandle<JSPropertyDescriptor> desc);
2501 bool
2502 nsWindowSH::NameStructEnabled(JSContext* aCx, nsGlobalWindow *aWin,
2503 const nsAString& aName,
2504 const nsGlobalNameStruct& aNameStruct)
2506 const nsGlobalNameStruct* nameStruct = &aNameStruct;
2507 if (nameStruct->mType == nsGlobalNameStruct::eTypeExternalClassInfoCreator) {
2508 nsresult rv = GetExternalClassInfo(GetNameSpaceManager(), aName, nameStruct,
2509 &nameStruct);
2510 if (NS_FAILED(rv) || !nameStruct) {
2511 return false;
2515 return (nameStruct->mType != nsGlobalNameStruct::eTypeProperty &&
2516 nameStruct->mType != nsGlobalNameStruct::eTypeClassConstructor &&
2517 nameStruct->mType != nsGlobalNameStruct::eTypeExternalClassInfo) ||
2518 OldBindingConstructorEnabled(nameStruct, aWin, aCx);
2521 #ifdef RELEASE_BUILD
2522 #define USE_CONTROLLERS_SHIM
2523 #endif
2525 #ifdef USE_CONTROLLERS_SHIM
2526 static const JSClass ControllersShimClass = {
2527 "XULControllers", 0,
2528 JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
2529 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, nullptr
2531 #endif
2533 // static
2534 nsresult
2535 nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
2536 JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
2537 JS::MutableHandle<JSPropertyDescriptor> desc)
2539 if (id == XPCJSRuntime::Get()->GetStringID(XPCJSRuntime::IDX_COMPONENTS)) {
2540 return LookupComponentsShim(cx, obj, aWin, desc);
2543 #ifdef USE_CONTROLLERS_SHIM
2544 // Note: We use |obj| rather than |aWin| to get the principal here, because
2545 // this is called during Window setup when the Document isn't necessarily
2546 // hooked up yet.
2547 if (id == XPCJSRuntime::Get()->GetStringID(XPCJSRuntime::IDX_CONTROLLERS) &&
2548 !xpc::IsXrayWrapper(obj) &&
2549 !nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(obj)))
2551 if (aWin->GetDoc()) {
2552 aWin->GetDoc()->WarnOnceAbout(nsIDocument::eWindow_Controllers);
2554 JS::Rooted<JSObject*> shim(cx, JS_NewObject(cx, &ControllersShimClass, JS::NullPtr(), obj));
2555 if (NS_WARN_IF(!shim)) {
2556 return NS_ERROR_OUT_OF_MEMORY;
2558 FillPropertyDescriptor(desc, obj, JS::ObjectValue(*shim), /* readOnly = */ false);
2559 return NS_OK;
2561 #endif
2563 nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
2564 NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
2566 // Note - Our only caller is nsGlobalWindow::DoNewResolve, which checks that
2567 // JSID_IS_STRING(id) is true.
2568 nsAutoJSString name;
2569 if (!name.init(cx, JSID_TO_STRING(id))) {
2570 return NS_ERROR_OUT_OF_MEMORY;
2573 const char16_t *class_name = nullptr;
2574 const nsGlobalNameStruct *name_struct =
2575 nameSpaceManager->LookupName(name, &class_name);
2577 if (!name_struct) {
2578 return NS_OK;
2581 // The class_name had better match our name
2582 MOZ_ASSERT(name.Equals(class_name));
2584 NS_ENSURE_TRUE(class_name, NS_ERROR_UNEXPECTED);
2586 nsresult rv = NS_OK;
2588 if (name_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfoCreator) {
2589 rv = GetExternalClassInfo(nameSpaceManager, name, name_struct,
2590 &name_struct);
2591 if (NS_FAILED(rv) || !name_struct) {
2592 return rv;
2596 if (name_struct->mType == nsGlobalNameStruct::eTypeNewDOMBinding ||
2597 name_struct->mType == nsGlobalNameStruct::eTypeInterface ||
2598 name_struct->mType == nsGlobalNameStruct::eTypeClassProto ||
2599 name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
2600 // Lookup new DOM bindings.
2601 DefineInterface getOrCreateInterfaceObject =
2602 name_struct->mDefineDOMInterface;
2603 if (getOrCreateInterfaceObject) {
2604 if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor &&
2605 !OldBindingConstructorEnabled(name_struct, aWin, cx)) {
2606 return NS_OK;
2609 ConstructorEnabled* checkEnabledForScope = name_struct->mConstructorEnabled;
2610 // We do the enabled check on the current compartment of cx, but for the
2611 // actual object we pass in the underlying object in the Xray case. That
2612 // way the callee can decide whether to allow access based on the caller
2613 // or the window being touched.
2614 JS::Rooted<JSObject*> global(cx,
2615 js::CheckedUnwrap(obj, /* stopAtOuter = */ false));
2616 if (!global) {
2617 return NS_ERROR_DOM_SECURITY_ERR;
2619 if (checkEnabledForScope && !checkEnabledForScope(cx, global)) {
2620 return NS_OK;
2623 // The DOM constructor resolve machinery interacts with Xrays in tricky
2624 // ways, and there are some asymmetries that are important to understand.
2626 // In the regular (non-Xray) case, we only want to resolve constructors
2627 // once (so that if they're deleted, they don't reappear). We do this by
2628 // stashing the constructor in a slot on the global, such that we can see
2629 // during resolve whether we've created it already. This is rather
2630 // memory-intensive, so we don't try to maintain these semantics when
2631 // manipulating a global over Xray (so the properties just re-resolve if
2632 // they've been deleted).
2634 // Unfortunately, there's a bit of an impedance-mismatch between the Xray
2635 // and non-Xray machinery. The Xray machinery wants an API that returns a
2636 // JSPropertyDescriptor, so that the resolve hook doesn't have to get
2637 // snared up with trying to define a property on the Xray holder. At the
2638 // same time, the DefineInterface callbacks are set up to define things
2639 // directly on the global. And re-jiggering them to return property
2640 // descriptors is tricky, because some DefineInterface callbacks define
2641 // multiple things (like the Image() alias for HTMLImageElement).
2643 // So the setup is as-follows:
2645 // * The resolve function takes a JSPropertyDescriptor, but in the
2646 // non-Xray case, callees may define things directly on the global, and
2647 // set the value on the property descriptor to |undefined| to indicate
2648 // that there's nothing more for the caller to do. We assert against
2649 // this behavior in the Xray case.
2651 // * We make sure that we do a non-Xray resolve first, so that all the
2652 // slots are set up. In the Xray case, this means unwrapping and doing
2653 // a non-Xray resolve before doing the Xray resolve.
2655 // This all could use some grand refactoring, but for now we just limp
2656 // along.
2657 if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
2658 JS::Rooted<JSObject*> interfaceObject(cx);
2660 JSAutoCompartment ac(cx, global);
2661 interfaceObject = getOrCreateInterfaceObject(cx, global, id, false);
2663 if (NS_WARN_IF(!interfaceObject)) {
2664 return NS_ERROR_FAILURE;
2666 if (!JS_WrapObject(cx, &interfaceObject)) {
2667 return NS_ERROR_FAILURE;
2670 FillPropertyDescriptor(desc, obj, 0, JS::ObjectValue(*interfaceObject));
2671 } else {
2672 JS::Rooted<JSObject*> interfaceObject(cx,
2673 getOrCreateInterfaceObject(cx, obj, id, true));
2674 if (NS_WARN_IF(!interfaceObject)) {
2675 return NS_ERROR_FAILURE;
2677 // We've already defined the property. We indicate this to the caller
2678 // by filling a property descriptor with JS::UndefinedValue() as the
2679 // value. We still have to fill in a property descriptor, though, so
2680 // that the caller knows the property is in fact on this object. It
2681 // doesn't matter what we pass for the "readonly" argument here.
2682 FillPropertyDescriptor(desc, obj, JS::UndefinedValue(), false);
2685 return NS_OK;
2689 if (name_struct->mType == nsGlobalNameStruct::eTypeInterface) {
2690 // We're resolving a name of a DOM interface for which there is no
2691 // direct DOM class, create a constructor object...
2692 nsRefPtr<nsDOMConstructor> constructor;
2693 rv = nsDOMConstructor::Create(class_name,
2694 nullptr,
2695 name_struct,
2696 static_cast<nsPIDOMWindow*>(aWin),
2697 getter_AddRefs(constructor));
2698 NS_ENSURE_SUCCESS(rv, rv);
2700 JS::Rooted<JS::Value> v(cx);
2701 js::AssertSameCompartment(cx, obj);
2702 rv = WrapNative(cx, constructor, &NS_GET_IID(nsIDOMDOMConstructor),
2703 false, &v);
2704 NS_ENSURE_SUCCESS(rv, rv);
2706 JS::Rooted<JSObject*> class_obj(cx, &v.toObject());
2708 // ... and define the constants from the DOM interface on that
2709 // constructor object.
2712 JSAutoCompartment ac(cx, class_obj);
2713 rv = DefineInterfaceConstants(cx, class_obj, &name_struct->mIID);
2714 NS_ENSURE_SUCCESS(rv, rv);
2717 if (!JS_WrapValue(cx, &v)) {
2718 return NS_ERROR_UNEXPECTED;
2721 FillPropertyDescriptor(desc, obj, 0, v);
2722 return NS_OK;
2725 if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor ||
2726 name_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfo) {
2727 if (!OldBindingConstructorEnabled(name_struct, aWin, cx)) {
2728 return NS_OK;
2731 // Create the XPConnect prototype for our classinfo, PostCreateProto will
2732 // set up the prototype chain. This will go ahead and define things on the
2733 // actual window's global.
2734 nsCOMPtr<nsIXPConnectJSObjectHolder> proto_holder;
2735 rv = GetXPCProto(sXPConnect, cx, aWin, name_struct,
2736 getter_AddRefs(proto_holder));
2737 NS_ENSURE_SUCCESS(rv, rv);
2738 bool isXray = xpc::WrapperFactory::IsXrayWrapper(obj);
2739 MOZ_ASSERT_IF(obj != aWin->GetGlobalJSObject(), isXray);
2740 if (!isXray) {
2741 // GetXPCProto already defined the property for us
2742 FillPropertyDescriptor(desc, obj, JS::UndefinedValue(), false);
2743 return NS_OK;
2746 // This is the Xray case. Look up the constructor object for this
2747 // prototype.
2748 JS::Rooted<JSObject*> dot_prototype(cx, proto_holder->GetJSObject());
2749 NS_ENSURE_STATE(dot_prototype);
2751 const nsDOMClassInfoData *ci_data;
2752 if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
2753 ci_data = &sClassInfoData[name_struct->mDOMClassInfoID];
2754 } else {
2755 ci_data = name_struct->mData;
2758 return ResolvePrototype(sXPConnect, aWin, cx, obj, class_name, ci_data,
2759 name_struct, nameSpaceManager, dot_prototype,
2760 desc);
2763 if (name_struct->mType == nsGlobalNameStruct::eTypeClassProto) {
2764 // We don't have a XPConnect prototype object, let ResolvePrototype create
2765 // one.
2766 return ResolvePrototype(sXPConnect, aWin, cx, obj, class_name, nullptr,
2767 name_struct, nameSpaceManager, nullptr, desc);
2770 if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias) {
2771 const nsGlobalNameStruct *alias_struct =
2772 nameSpaceManager->GetConstructorProto(name_struct);
2773 NS_ENSURE_TRUE(alias_struct, NS_ERROR_UNEXPECTED);
2775 // We need to use the XPConnect prototype for the DOM class that this
2776 // constructor is an alias for (for example for Image we need the prototype
2777 // for HTMLImageElement).
2778 nsCOMPtr<nsIXPConnectJSObjectHolder> proto_holder;
2779 rv = GetXPCProto(sXPConnect, cx, aWin, alias_struct,
2780 getter_AddRefs(proto_holder));
2781 NS_ENSURE_SUCCESS(rv, rv);
2783 JSObject* dot_prototype = proto_holder->GetJSObject();
2784 NS_ENSURE_STATE(dot_prototype);
2786 const nsDOMClassInfoData *ci_data;
2787 if (alias_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
2788 ci_data = &sClassInfoData[alias_struct->mDOMClassInfoID];
2789 } else if (alias_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfo) {
2790 ci_data = alias_struct->mData;
2791 } else {
2792 return NS_ERROR_UNEXPECTED;
2795 return ResolvePrototype(sXPConnect, aWin, cx, obj, class_name, ci_data,
2796 name_struct, nameSpaceManager, nullptr, desc);
2799 if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructor) {
2800 nsRefPtr<nsDOMConstructor> constructor;
2801 rv = nsDOMConstructor::Create(class_name, nullptr, name_struct,
2802 static_cast<nsPIDOMWindow*>(aWin),
2803 getter_AddRefs(constructor));
2804 NS_ENSURE_SUCCESS(rv, rv);
2806 JS::Rooted<JS::Value> val(cx);
2807 js::AssertSameCompartment(cx, obj);
2808 rv = WrapNative(cx, constructor, &NS_GET_IID(nsIDOMDOMConstructor),
2809 true, &val);
2810 NS_ENSURE_SUCCESS(rv, rv);
2812 NS_ASSERTION(val.isObject(), "Why didn't we get a JSObject?");
2814 FillPropertyDescriptor(desc, obj, 0, val);
2816 return NS_OK;
2819 if (name_struct->mType == nsGlobalNameStruct::eTypeProperty) {
2820 if (!OldBindingConstructorEnabled(name_struct, aWin, cx))
2821 return NS_OK;
2823 // Before defining a global property, check for a named subframe of the
2824 // same name. If it exists, we don't want to shadow it.
2825 nsCOMPtr<nsIDOMWindow> childWin = aWin->GetChildWindow(name);
2826 if (childWin)
2827 return NS_OK;
2829 nsCOMPtr<nsISupports> native(do_CreateInstance(name_struct->mCID, &rv));
2830 NS_ENSURE_SUCCESS(rv, rv);
2832 JS::Rooted<JS::Value> prop_val(cx, JS::UndefinedValue()); // Property value.
2834 nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi(do_QueryInterface(native));
2835 if (gpi) {
2836 rv = gpi->Init(aWin, &prop_val);
2837 NS_ENSURE_SUCCESS(rv, rv);
2840 if (prop_val.isPrimitive() && !prop_val.isNull()) {
2841 if (aWin->IsOuterWindow()) {
2842 nsGlobalWindow *inner = aWin->GetCurrentInnerWindowInternal();
2843 NS_ENSURE_TRUE(inner, NS_ERROR_UNEXPECTED);
2846 rv = WrapNative(cx, native, true, &prop_val);
2849 NS_ENSURE_SUCCESS(rv, rv);
2851 if (!JS_WrapValue(cx, &prop_val)) {
2852 return NS_ERROR_UNEXPECTED;
2855 FillPropertyDescriptor(desc, obj, prop_val, false);
2857 return NS_OK;
2860 return rv;
2863 template<class Interface>
2864 static nsresult
2865 LocationSetterGuts(JSContext *cx, JSObject *obj, JS::MutableHandle<JS::Value> vp)
2867 // This function duplicates some of the logic in XPC_WN_HelperSetProperty
2868 obj = js::CheckedUnwrap(obj, /* stopAtOuter = */ false);
2869 if (!IS_WN_REFLECTOR(obj))
2870 return NS_ERROR_XPC_BAD_CONVERT_JS;
2871 XPCWrappedNative *wrapper = XPCWrappedNative::Get(obj);
2873 // The error checks duplicate code in THROW_AND_RETURN_IF_BAD_WRAPPER
2874 NS_ENSURE_TRUE(!wrapper || wrapper->IsValid(), NS_ERROR_XPC_HAS_BEEN_SHUTDOWN);
2876 nsCOMPtr<Interface> xpcomObj = do_QueryWrappedNative(wrapper, obj);
2877 NS_ENSURE_TRUE(xpcomObj, NS_ERROR_UNEXPECTED);
2879 nsCOMPtr<nsIDOMLocation> location;
2880 nsresult rv = xpcomObj->GetLocation(getter_AddRefs(location));
2881 NS_ENSURE_SUCCESS(rv, rv);
2883 // Grab the value we're being set to before we stomp on |vp|
2884 JS::Rooted<JSString*> val(cx, JS::ToString(cx, vp));
2885 NS_ENSURE_TRUE(val, NS_ERROR_UNEXPECTED);
2887 // Make sure |val| stays alive below
2888 JS::Anchor<JSString *> anchor(val);
2890 // We have to wrap location into vp before null-checking location, to
2891 // avoid assigning the wrong thing into the slot.
2892 rv = WrapNative(cx, location, &NS_GET_IID(nsIDOMLocation), true, vp);
2893 NS_ENSURE_SUCCESS(rv, rv);
2895 if (!location) {
2896 // Make this a no-op
2897 return NS_OK;
2900 nsAutoJSString str;
2901 NS_ENSURE_TRUE(str.init(cx, val), NS_ERROR_UNEXPECTED);
2903 return location->SetHref(str);
2906 template<class Interface>
2907 static bool
2908 LocationSetter(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, bool strict,
2909 JS::MutableHandle<JS::Value> vp)
2911 nsresult rv = LocationSetterGuts<Interface>(cx, obj, vp);
2912 if (NS_FAILED(rv)) {
2913 xpc::Throw(cx, rv);
2914 return false;
2917 return true;
2920 static bool
2921 LocationSetterUnwrapper(JSContext *cx, JS::Handle<JSObject*> obj_, JS::Handle<jsid> id,
2922 bool strict, JS::MutableHandle<JS::Value> vp)
2924 JS::Rooted<JSObject*> obj(cx, obj_);
2926 JSObject *wrapped = XPCWrapper::UnsafeUnwrapSecurityWrapper(obj);
2927 if (wrapped) {
2928 obj = wrapped;
2931 return LocationSetter<nsIDOMWindow>(cx, obj, id, strict, vp);
2934 struct InterfaceShimEntry {
2935 const char *geckoName;
2936 const char *domName;
2939 // We add shims from Components.interfaces.nsIDOMFoo to window.Foo for each
2940 // interface that has interface constants that sites might be getting off
2941 // of Ci.
2942 const InterfaceShimEntry kInterfaceShimMap[] =
2943 { { "nsIDOMFileReader", "FileReader" },
2944 { "nsIXMLHttpRequest", "XMLHttpRequest" },
2945 { "nsIDOMDOMException", "DOMException" },
2946 { "nsIDOMNode", "Node" },
2947 { "nsIDOMCSSPrimitiveValue", "CSSPrimitiveValue" },
2948 { "nsIDOMCSSRule", "CSSRule" },
2949 { "nsIDOMCSSValue", "CSSValue" },
2950 { "nsIDOMEvent", "Event" },
2951 { "nsIDOMNSEvent", "Event" },
2952 { "nsIDOMKeyEvent", "KeyEvent" },
2953 { "nsIDOMMouseEvent", "MouseEvent" },
2954 { "nsIDOMMouseScrollEvent", "MouseScrollEvent" },
2955 { "nsIDOMMutationEvent", "MutationEvent" },
2956 { "nsIDOMSimpleGestureEvent", "SimpleGestureEvent" },
2957 { "nsIDOMUIEvent", "UIEvent" },
2958 { "nsIDOMHTMLMediaElement", "HTMLMediaElement" },
2959 { "nsIDOMMediaError", "MediaError" },
2960 { "nsIDOMOfflineResourceList", "OfflineResourceList" },
2961 { "nsIDOMRange", "Range" },
2962 { "nsIDOMSVGLength", "SVGLength" },
2963 { "nsIDOMNodeFilter", "NodeFilter" },
2964 { "nsIDOMXPathResult", "XPathResult" } };
2966 static nsresult
2967 LookupComponentsShim(JSContext *cx, JS::Handle<JSObject*> global,
2968 nsPIDOMWindow *win,
2969 JS::MutableHandle<JSPropertyDescriptor> desc)
2971 // Keep track of how often this happens.
2972 Telemetry::Accumulate(Telemetry::COMPONENTS_SHIM_ACCESSED_BY_CONTENT, true);
2974 // Warn once.
2975 nsCOMPtr<nsIDocument> doc = win->GetExtantDoc();
2976 if (doc) {
2977 doc->WarnOnceAbout(nsIDocument::eComponents, /* asError = */ true);
2980 // Create a fake Components object.
2981 JS::Rooted<JSObject*> components(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), global));
2982 NS_ENSURE_TRUE(components, NS_ERROR_OUT_OF_MEMORY);
2984 // Create a fake interfaces object.
2985 JS::Rooted<JSObject*> interfaces(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), global));
2986 NS_ENSURE_TRUE(interfaces, NS_ERROR_OUT_OF_MEMORY);
2987 bool ok =
2988 JS_DefineProperty(cx, components, "interfaces", interfaces,
2989 JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY,
2990 JS_PropertyStub, JS_StrictPropertyStub);
2991 NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
2993 // Define a bunch of shims from the Ci.nsIDOMFoo to window.Foo for DOM
2994 // interfaces with constants.
2995 for (uint32_t i = 0; i < ArrayLength(kInterfaceShimMap); ++i) {
2997 // Grab the names from the table.
2998 const char *geckoName = kInterfaceShimMap[i].geckoName;
2999 const char *domName = kInterfaceShimMap[i].domName;
3001 // Look up the appopriate interface object on the global.
3002 JS::Rooted<JS::Value> v(cx, JS::UndefinedValue());
3003 ok = JS_GetProperty(cx, global, domName, &v);
3004 NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
3005 if (!v.isObject()) {
3006 NS_WARNING("Unable to find interface object on global");
3007 continue;
3010 // Define the shim on the interfaces object.
3011 ok = JS_DefineProperty(cx, interfaces, geckoName, v,
3012 JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY,
3013 JS_PropertyStub, JS_StrictPropertyStub);
3014 NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
3017 FillPropertyDescriptor(desc, global, JS::ObjectValue(*components), false);
3019 return NS_OK;
3022 NS_IMETHODIMP
3023 nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
3024 JSObject *obj_, jsid id_, JSObject **objp,
3025 bool *_retval)
3027 JS::Rooted<JSObject*> obj(cx, obj_);
3028 JS::Rooted<jsid> id(cx, id_);
3030 if (!JSID_IS_STRING(id)) {
3031 return NS_OK;
3034 MOZ_ASSERT(*_retval == true); // guaranteed by XPC_WN_Helper_NewResolve
3036 nsGlobalWindow *win = nsGlobalWindow::FromWrapper(wrapper);
3037 MOZ_ASSERT(win->IsInnerWindow());
3039 // Don't resolve standard classes on XrayWrappers, only resolve them if we're
3040 // resolving on the real global object.
3041 bool isXray = xpc::WrapperFactory::IsXrayWrapper(obj);
3042 if (!isXray) {
3043 bool did_resolve = false;
3044 if (!JS_ResolveStandardClass(cx, obj, id, &did_resolve)) {
3045 // Return NS_OK to avoid stomping over the exception that was passed
3046 // down from the ResolveStandardClass call.
3047 *_retval = false;
3048 return NS_OK;
3051 if (did_resolve) {
3052 *objp = obj;
3053 return NS_OK;
3057 // WebIDL quickstubs handle location for us, but Xrays don't see those. So if
3058 // we're an Xray, we have to resolve stuff here to make "window.location =
3059 // someString" work.
3060 if (sLocation_id == id && isXray) {
3061 nsCOMPtr<nsIDOMLocation> location;
3062 nsresult rv = win->GetLocation(getter_AddRefs(location));
3063 NS_ENSURE_SUCCESS(rv, rv);
3065 JS::Rooted<JS::Value> v(cx);
3066 rv = WrapNative(cx, location, &NS_GET_IID(nsIDOMLocation), true, &v);
3067 NS_ENSURE_SUCCESS(rv, rv);
3069 bool ok = JS_DefinePropertyById(cx, obj, id, v,
3070 JSPROP_PERMANENT | JSPROP_ENUMERATE,
3071 JS_PropertyStub, LocationSetterUnwrapper);
3073 if (!ok) {
3074 return NS_ERROR_FAILURE;
3077 *objp = obj;
3079 return NS_OK;
3082 // WebIDL quickstubs handle "top" for us, but Xrays don't see those. So if
3083 // we're an Xray and we want "top" to be JSPROP_PERMANENT, we need to resolve
3084 // it here.
3085 if (sTop_id == id && isXray) {
3086 nsCOMPtr<nsIDOMWindow> top;
3087 nsresult rv = win->GetScriptableTop(getter_AddRefs(top));
3088 NS_ENSURE_SUCCESS(rv, rv);
3090 JS::Rooted<JS::Value> v(cx);
3091 js::AssertSameCompartment(cx, obj);
3092 rv = WrapNative(cx, top, &NS_GET_IID(nsIDOMWindow), true, &v);
3093 NS_ENSURE_SUCCESS(rv, rv);
3095 // Hold on to the top window object as a global property so we
3096 // don't need to worry about losing expando properties etc.
3097 if (!JS_DefinePropertyById(cx, obj, id, v,
3098 JSPROP_READONLY | JSPROP_PERMANENT |
3099 JSPROP_ENUMERATE,
3100 JS_PropertyStub, JS_StrictPropertyStub)) {
3101 return NS_ERROR_FAILURE;
3103 *objp = obj;
3105 return NS_OK;
3108 if (isXray) {
3109 // We promise to resolve on the underlying object first. That will create
3110 // the actual interface object if needed and store it in a data structure
3111 // hanging off the global. Then our second call will wrap up in an Xray as
3112 // needed. We do things this way because we use the existence of the
3113 // object in that data structure as a flag that indicates that its name
3114 // (and any relevant named constructor names) has been resolved before;
3115 // this allows us to avoid re-resolving in the Xray case if the property is
3116 // deleted by page script.
3117 JS::Rooted<JSObject*> global(cx,
3118 js::UncheckedUnwrap(obj, /* stopAtOuter = */ false));
3119 JSAutoCompartment ac(cx, global);
3120 JS::Rooted<JSPropertyDescriptor> desc(cx);
3121 if (!win->DoNewResolve(cx, global, id, &desc)) {
3122 return NS_ERROR_FAILURE;
3124 // If we have an object here, that means we resolved the property.
3125 // But if the value is undefined, that means that GlobalResolve
3126 // also already defined it, so we don't have to.
3127 if (desc.object() && !desc.value().isUndefined() &&
3128 !JS_DefinePropertyById(cx, global, id, desc.value(),
3129 desc.attributes(),
3130 desc.getter(), desc.setter())) {
3131 return NS_ERROR_FAILURE;
3135 JS::Rooted<JSPropertyDescriptor> desc(cx);
3136 if (!win->DoNewResolve(cx, obj, id, &desc)) {
3137 return NS_ERROR_FAILURE;
3139 if (desc.object()) {
3140 // If we have an object here, that means we resolved the property.
3141 // But if the value is undefined, that means that GlobalResolve
3142 // also already defined it, so we don't have to. Note that in the
3143 // Xray case we should never see undefined.
3144 MOZ_ASSERT_IF(isXray, !desc.value().isUndefined());
3145 if (!desc.value().isUndefined() &&
3146 !JS_DefinePropertyById(cx, obj, id, desc.value(),
3147 desc.attributes(),
3148 desc.getter(), desc.setter())) {
3149 return NS_ERROR_FAILURE;
3152 *objp = obj;
3153 return NS_OK;
3156 if (sDocument_id == id) {
3157 nsCOMPtr<nsIDocument> document = win->GetDoc();
3158 JS::Rooted<JS::Value> v(cx);
3159 nsresult rv = WrapNative(cx, document, document,
3160 &NS_GET_IID(nsIDOMDocument), &v, false);
3161 NS_ENSURE_SUCCESS(rv, rv);
3163 // nsIDocument::WrapObject will handle defining the property.
3164 *objp = obj;
3166 // NB: We need to do this for any Xray wrapper.
3167 if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
3168 *_retval = JS_WrapValue(cx, &v) &&
3169 JS_DefineProperty(cx, obj, "document", v,
3170 JSPROP_READONLY | JSPROP_ENUMERATE,
3171 JS_PropertyStub, JS_StrictPropertyStub);
3172 if (!*_retval) {
3173 return NS_ERROR_UNEXPECTED;
3177 return NS_OK;
3180 return nsDOMGenericSH::NewResolve(wrapper, cx, obj, id, objp, _retval);
3183 NS_IMETHODIMP
3184 nsWindowSH::OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
3185 JSObject * obj, JSObject * *_retval)
3187 nsGlobalWindow *origWin = nsGlobalWindow::FromWrapper(wrapper);
3188 nsGlobalWindow *win = origWin->GetOuterWindowInternal();
3190 if (!win) {
3191 // If we no longer have an outer window. No code should ever be
3192 // running on a window w/o an outer, which means this hook should
3193 // never be called when we have no outer. But just in case, return
3194 // null to prevent leaking an inner window to code in a different
3195 // window.
3196 *_retval = nullptr;
3197 return NS_ERROR_UNEXPECTED;
3200 JS::Rooted<JSObject*> winObj(cx, win->FastGetGlobalJSObject());
3201 MOZ_ASSERT(winObj);
3203 // Note that while |wrapper| is same-compartment with cx, the outer window
3204 // might not be. If we're running script in an inactive scope and evalute
3205 // |this|, the outer window is actually a cross-compartment wrapper. So we
3206 // need to wrap here.
3207 if (!JS_WrapObject(cx, &winObj)) {
3208 *_retval = nullptr;
3209 return NS_ERROR_UNEXPECTED;
3212 *_retval = winObj;
3213 return NS_OK;
3216 // EventTarget helper
3218 NS_IMETHODIMP
3219 nsEventTargetSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
3220 JSObject *aGlobalObj, JSObject **parentObj)
3222 JS::Rooted<JSObject*> globalObj(cx, aGlobalObj);
3223 DOMEventTargetHelper* target = DOMEventTargetHelper::FromSupports(nativeObj);
3225 nsCOMPtr<nsIScriptGlobalObject> native_parent;
3226 target->GetParentObject(getter_AddRefs(native_parent));
3228 *parentObj = native_parent ? native_parent->GetGlobalJSObject() : globalObj;
3230 return *parentObj ? NS_OK : NS_ERROR_FAILURE;
3233 NS_IMETHODIMP
3234 nsEventTargetSH::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
3235 JSObject *obj, jsid id, jsval *vp, bool *_retval)
3237 nsEventTargetSH::PreserveWrapper(GetNative(wrapper, obj));
3239 return NS_OK;
3242 void
3243 nsEventTargetSH::PreserveWrapper(nsISupports *aNative)
3245 DOMEventTargetHelper* target = DOMEventTargetHelper::FromSupports(aNative);
3246 target->PreserveWrapper(aNative);
3249 // nsIDOMEventListener::HandleEvent() 'this' converter helper
3251 NS_INTERFACE_MAP_BEGIN(nsEventListenerThisTranslator)
3252 NS_INTERFACE_MAP_ENTRY(nsIXPCFunctionThisTranslator)
3253 NS_INTERFACE_MAP_ENTRY(nsISupports)
3254 NS_INTERFACE_MAP_END
3257 NS_IMPL_ADDREF(nsEventListenerThisTranslator)
3258 NS_IMPL_RELEASE(nsEventListenerThisTranslator)
3261 NS_IMETHODIMP
3262 nsEventListenerThisTranslator::TranslateThis(nsISupports *aInitialThis,
3263 nsISupports **_retval)
3265 nsCOMPtr<nsIDOMEvent> event(do_QueryInterface(aInitialThis));
3266 NS_ENSURE_TRUE(event, NS_ERROR_UNEXPECTED);
3268 nsCOMPtr<EventTarget> target = event->InternalDOMEvent()->GetCurrentTarget();
3269 target.forget(_retval);
3270 return NS_OK;
3273 NS_IMETHODIMP
3274 nsDOMConstructorSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
3275 JSObject *aGlobalObj, JSObject **parentObj)
3277 JS::Rooted<JSObject*> globalObj(cx, aGlobalObj);
3278 nsDOMConstructor *wrapped = static_cast<nsDOMConstructor *>(nativeObj);
3280 #ifdef DEBUG
3282 nsCOMPtr<nsIDOMDOMConstructor> is_constructor =
3283 do_QueryInterface(nativeObj);
3284 NS_ASSERTION(is_constructor, "How did we not get a constructor?");
3286 #endif
3288 return wrapped->PreCreate(cx, globalObj, parentObj);
3291 NS_IMETHODIMP
3292 nsDOMConstructorSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
3293 JSObject *aObj, jsid aId, JSObject **objp,
3294 bool *_retval)
3296 JS::Rooted<JSObject*> obj(cx, aObj);
3297 JS::Rooted<jsid> id(cx, aId);
3298 // For regular DOM constructors, we have our interface constants defined on
3299 // us by nsWindowSH::GlobalResolve. However, XrayWrappers can't see these
3300 // interface constants (as they look like expando properties) so we have to
3301 // specially resolve those constants here, but only for Xray wrappers.
3302 if (!ObjectIsNativeWrapper(cx, obj)) {
3303 return NS_OK;
3306 JS::Rooted<JSObject*> nativePropsObj(cx, xpc::XrayUtils::GetNativePropertiesObject(cx, obj));
3307 nsDOMConstructor *wrapped =
3308 static_cast<nsDOMConstructor *>(wrapper->Native());
3309 nsresult rv = wrapped->ResolveInterfaceConstants(cx, nativePropsObj);
3310 NS_ENSURE_SUCCESS(rv, rv);
3312 // Now re-lookup the ID to see if we should report back that we resolved the
3313 // looked-for constant. Note that we don't have to worry about infinitely
3314 // recurring back here because the Xray wrapper's holder object doesn't call
3315 // NewResolve hooks.
3316 bool found;
3317 if (!JS_HasPropertyById(cx, nativePropsObj, id, &found)) {
3318 *_retval = false;
3319 return NS_OK;
3322 if (found) {
3323 *objp = obj;
3325 return NS_OK;
3328 NS_IMETHODIMP
3329 nsDOMConstructorSH::Call(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
3330 JSObject *aObj, const JS::CallArgs &args, bool *_retval)
3332 JS::Rooted<JSObject*> obj(cx, aObj);
3333 MOZ_ASSERT(obj);
3335 nsDOMConstructor *wrapped =
3336 static_cast<nsDOMConstructor *>(wrapper->Native());
3338 #ifdef DEBUG
3340 nsCOMPtr<nsIDOMDOMConstructor> is_constructor =
3341 do_QueryWrappedNative(wrapper);
3342 NS_ASSERTION(is_constructor, "How did we not get a constructor?");
3344 #endif
3346 return wrapped->Construct(wrapper, cx, obj, args, _retval);
3349 NS_IMETHODIMP
3350 nsDOMConstructorSH::Construct(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
3351 JSObject *aObj, const JS::CallArgs &args, bool *_retval)
3353 JS::Rooted<JSObject*> obj(cx, aObj);
3354 MOZ_ASSERT(obj);
3356 nsDOMConstructor *wrapped =
3357 static_cast<nsDOMConstructor *>(wrapper->Native());
3359 #ifdef DEBUG
3361 nsCOMPtr<nsIDOMDOMConstructor> is_constructor =
3362 do_QueryWrappedNative(wrapper);
3363 NS_ASSERTION(is_constructor, "How did we not get a constructor?");
3365 #endif
3367 return wrapped->Construct(wrapper, cx, obj, args, _retval);
3370 NS_IMETHODIMP
3371 nsDOMConstructorSH::HasInstance(nsIXPConnectWrappedNative *wrapper,
3372 JSContext *cx, JSObject *aObj, JS::Handle<JS::Value> val,
3373 bool *bp, bool *_retval)
3375 JS::Rooted<JSObject*> obj(cx, aObj);
3376 nsDOMConstructor *wrapped =
3377 static_cast<nsDOMConstructor *>(wrapper->Native());
3379 #ifdef DEBUG
3381 nsCOMPtr<nsIDOMDOMConstructor> is_constructor =
3382 do_QueryWrappedNative(wrapper);
3383 NS_ASSERTION(is_constructor, "How did we not get a constructor?");
3385 #endif
3387 return wrapped->HasInstance(wrapper, cx, obj, val, bp, _retval);
3390 NS_IMETHODIMP
3391 nsNonDOMObjectSH::GetFlags(uint32_t *aFlags)
3393 // This is NOT a DOM Object. Use this helper class for cases when you need
3394 // to do something like implement nsISecurityCheckedComponent in a meaningful
3395 // way.
3396 *aFlags = nsIClassInfo::MAIN_THREAD_ONLY | nsIClassInfo::SINGLETON_CLASSINFO;
3397 return NS_OK;