Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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/. */
6 :
7 : #include "mozilla/ArrayUtils.h"
8 :
9 : #ifdef XP_WIN
10 : #undef GetClassName
11 : #endif
12 :
13 : // JavaScript includes
14 : #include "jsapi.h"
15 : #include "jsfriendapi.h"
16 : #include "WrapperFactory.h"
17 : #include "AccessCheck.h"
18 : #include "XrayWrapper.h"
19 :
20 : #include "xpcpublic.h"
21 : #include "xpcprivate.h"
22 : #include "xpc_make_class.h"
23 : #include "XPCWrapper.h"
24 :
25 : #include "mozilla/DOMEventTargetHelper.h"
26 : #include "mozilla/dom/RegisterBindings.h"
27 :
28 : #include "nscore.h"
29 : #include "nsDOMClassInfo.h"
30 : #include "nsIDOMClassInfo.h"
31 : #include "nsCRT.h"
32 : #include "nsCRTGlue.h"
33 : #include "nsICategoryManager.h"
34 : #include "nsIComponentRegistrar.h"
35 : #include "nsXPCOM.h"
36 : #include "nsISimpleEnumerator.h"
37 : #include "nsISupportsPrimitives.h"
38 : #include "nsIXPConnect.h"
39 : #include "xptcall.h"
40 : #include "nsTArray.h"
41 :
42 : // General helper includes
43 : #include "nsGlobalWindow.h"
44 : #include "nsIContent.h"
45 : #include "nsIDocument.h"
46 : #include "nsIDOMDocument.h"
47 : #include "nsIDOMEvent.h"
48 : #include "nsIDOMEventListener.h"
49 : #include "nsContentUtils.h"
50 : #include "nsIDOMGlobalPropertyInitializer.h"
51 : #include "mozilla/Attributes.h"
52 : #include "mozilla/Telemetry.h"
53 :
54 : // Window scriptable helper includes
55 : #include "nsScriptNameSpaceManager.h"
56 :
57 : // DOM base includes
58 : #include "nsIDOMWindow.h"
59 : #include "nsPIDOMWindow.h"
60 : #include "nsIDOMConstructor.h"
61 :
62 : // DOM core includes
63 : #include "nsError.h"
64 : #include "nsIDOMXULButtonElement.h"
65 : #include "nsIDOMXULCheckboxElement.h"
66 : #include "nsIDOMXULPopupElement.h"
67 :
68 : // Event related includes
69 : #include "nsIDOMEventTarget.h"
70 :
71 : // CSS related includes
72 : #include "nsIDOMCSSRule.h"
73 : #include "nsMemory.h"
74 :
75 : // includes needed for the prototype chain interfaces
76 :
77 : #include "nsIEventListenerService.h"
78 : #include "nsIMessageManager.h"
79 :
80 : #include "mozilla/dom/TouchEvent.h"
81 :
82 : #include "nsWrapperCacheInlines.h"
83 : #include "mozilla/dom/HTMLCollectionBinding.h"
84 :
85 : #include "nsDebug.h"
86 :
87 : #include "mozilla/dom/BindingUtils.h"
88 : #include "mozilla/Likely.h"
89 : #include "nsIInterfaceInfoManager.h"
90 :
91 : #ifdef MOZ_TIME_MANAGER
92 : #include "TimeManager.h"
93 : #endif
94 :
95 : using namespace mozilla;
96 : using namespace mozilla::dom;
97 :
98 : // NOTE: DEFAULT_SCRIPTABLE_FLAGS and DOM_DEFAULT_SCRIPTABLE_FLAGS
99 : // are defined in nsIDOMClassInfo.h.
100 :
101 : #define DOMCLASSINFO_STANDARD_FLAGS \
102 : (nsIClassInfo::MAIN_THREAD_ONLY | \
103 : nsIClassInfo::DOM_OBJECT | \
104 : nsIClassInfo::SINGLETON_CLASSINFO)
105 :
106 :
107 : #ifdef DEBUG
108 : #define NS_DEFINE_CLASSINFO_DATA_DEBUG(_class) \
109 : eDOMClassInfo_##_class##_id,
110 : #else
111 : #define NS_DEFINE_CLASSINFO_DATA_DEBUG(_class) \
112 : // nothing
113 : #endif
114 :
115 : #define NS_DEFINE_CLASSINFO_DATA_HELPER(_class, _helper, _flags, \
116 : _chromeOnly, _allowXBL) \
117 : { nullptr, \
118 : XPC_MAKE_CLASS_OPS(_flags), \
119 : XPC_MAKE_CLASS(#_class, _flags, \
120 : &sClassInfoData[eDOMClassInfo_##_class##_id].mClassOps), \
121 : _helper::doCreate, \
122 : nullptr, \
123 : nullptr, \
124 : nullptr, \
125 : _flags, \
126 : true, \
127 : _chromeOnly, \
128 : _allowXBL, \
129 : false, \
130 : NS_DEFINE_CLASSINFO_DATA_DEBUG(_class) \
131 : },
132 :
133 : #define NS_DEFINE_CLASSINFO_DATA(_class, _helper, _flags) \
134 : NS_DEFINE_CLASSINFO_DATA_HELPER(_class, _helper, _flags, false, false)
135 :
136 : #define NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(_class, _helper, _flags) \
137 : NS_DEFINE_CLASSINFO_DATA_HELPER(_class, _helper, _flags, true, false)
138 :
139 : #define NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(_class, _helper, _flags) \
140 : NS_DEFINE_CLASSINFO_DATA_HELPER(_class, _helper, _flags, true, true)
141 :
142 :
143 : // This list of NS_DEFINE_CLASSINFO_DATA macros is what gives the DOM
144 : // classes their correct behavior when used through XPConnect. The
145 : // arguments that are passed to NS_DEFINE_CLASSINFO_DATA are
146 : //
147 : // 1. Class name as it should appear in JavaScript, this name is also
148 : // used to find the id of the class in nsDOMClassInfo
149 : // (i.e. e<classname>_id)
150 : // 2. Scriptable helper class
151 : // 3. nsIClassInfo/nsIXPCScriptable flags (i.e. for GetScriptableFlags)
152 :
153 : static nsDOMClassInfoData sClassInfoData[] = {
154 : // Base classes
155 :
156 : NS_DEFINE_CLASSINFO_DATA(DOMPrototype, nsDOMConstructorSH,
157 : DOM_BASE_SCRIPTABLE_FLAGS |
158 : XPC_SCRIPTABLE_WANT_PRECREATE |
159 : XPC_SCRIPTABLE_WANT_RESOLVE |
160 : XPC_SCRIPTABLE_WANT_HASINSTANCE |
161 : XPC_SCRIPTABLE_DONT_ENUM_QUERY_INTERFACE)
162 : NS_DEFINE_CLASSINFO_DATA(DOMConstructor, nsDOMConstructorSH,
163 : DOM_BASE_SCRIPTABLE_FLAGS |
164 : XPC_SCRIPTABLE_WANT_PRECREATE |
165 : XPC_SCRIPTABLE_WANT_RESOLVE |
166 : XPC_SCRIPTABLE_WANT_HASINSTANCE |
167 : XPC_SCRIPTABLE_WANT_CALL |
168 : XPC_SCRIPTABLE_WANT_CONSTRUCT |
169 : XPC_SCRIPTABLE_DONT_ENUM_QUERY_INTERFACE)
170 :
171 : // Misc Core related classes
172 :
173 : NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ContentFrameMessageManager,
174 : nsMessageManagerSH<nsEventTargetSH>,
175 : DOM_DEFAULT_SCRIPTABLE_FLAGS |
176 : XPC_SCRIPTABLE_WANT_ENUMERATE |
177 : XPC_SCRIPTABLE_IS_GLOBAL_OBJECT)
178 : NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ContentProcessMessageManager,
179 : nsMessageManagerSH<nsDOMGenericSH>,
180 : DOM_DEFAULT_SCRIPTABLE_FLAGS |
181 : XPC_SCRIPTABLE_WANT_ENUMERATE |
182 : XPC_SCRIPTABLE_IS_GLOBAL_OBJECT)
183 : NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ChromeMessageBroadcaster, nsDOMGenericSH,
184 : DOM_DEFAULT_SCRIPTABLE_FLAGS)
185 : NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ChromeMessageSender, nsDOMGenericSH,
186 : DOM_DEFAULT_SCRIPTABLE_FLAGS)
187 :
188 :
189 : NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULControlElement, nsDOMGenericSH,
190 : DOM_DEFAULT_SCRIPTABLE_FLAGS)
191 : NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULLabeledControlElement, nsDOMGenericSH,
192 : DOM_DEFAULT_SCRIPTABLE_FLAGS)
193 : NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULButtonElement, nsDOMGenericSH,
194 : DOM_DEFAULT_SCRIPTABLE_FLAGS)
195 : NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULCheckboxElement, nsDOMGenericSH,
196 : DOM_DEFAULT_SCRIPTABLE_FLAGS)
197 : NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULPopupElement, nsDOMGenericSH,
198 : DOM_DEFAULT_SCRIPTABLE_FLAGS)
199 : };
200 :
201 : nsIXPConnect *nsDOMClassInfo::sXPConnect = nullptr;
202 : bool nsDOMClassInfo::sIsInitialized = false;
203 :
204 :
205 3 : jsid nsDOMClassInfo::sConstructor_id = JSID_VOID;
206 3 : jsid nsDOMClassInfo::sWrappedJSObject_id = JSID_VOID;
207 :
208 : static const JSClass *sObjectClass = nullptr;
209 :
210 : /**
211 : * Set our JSClass pointer for the Object class
212 : */
213 : static void
214 1 : FindObjectClass(JSContext* cx, JSObject* aGlobalObject)
215 : {
216 1 : NS_ASSERTION(!sObjectClass,
217 : "Double set of sObjectClass");
218 2 : JS::Rooted<JSObject*> obj(cx), proto(cx, aGlobalObject);
219 2 : do {
220 2 : obj = proto;
221 2 : js::GetObjectProto(cx, obj, &proto);
222 2 : } while (proto);
223 :
224 1 : sObjectClass = js::GetObjectJSClass(obj);
225 1 : }
226 :
227 : // Helper to handle torn-down inner windows.
228 : static inline nsresult
229 2 : SetParentToWindow(nsGlobalWindow *win, JSObject **parent)
230 : {
231 2 : MOZ_ASSERT(win);
232 2 : MOZ_ASSERT(win->IsInnerWindow());
233 2 : *parent = win->FastGetGlobalJSObject();
234 :
235 2 : if (MOZ_UNLIKELY(!*parent)) {
236 : // The inner window has been torn down. The scope is dying, so don't create
237 : // any new wrappers.
238 0 : return NS_ERROR_FAILURE;
239 : }
240 2 : return NS_OK;
241 : }
242 :
243 : // static
244 :
245 : nsISupports *
246 0 : nsDOMClassInfo::GetNative(nsIXPConnectWrappedNative *wrapper, JSObject *obj)
247 : {
248 0 : return wrapper ? wrapper->Native() : static_cast<nsISupports*>(js::GetObjectPrivate(obj));
249 : }
250 :
251 : nsresult
252 3 : nsDOMClassInfo::DefineStaticJSVals()
253 : {
254 6 : AutoJSAPI jsapi;
255 3 : if (!jsapi.Init(xpc::UnprivilegedJunkScope())) {
256 0 : return NS_ERROR_UNEXPECTED;
257 : }
258 3 : JSContext* cx = jsapi.cx();
259 :
260 : #define SET_JSID_TO_STRING(_id, _cx, _str) \
261 : if (JSString *str = ::JS_AtomizeAndPinString(_cx, _str)) \
262 : _id = INTERNED_STRING_TO_JSID(_cx, str); \
263 : else \
264 : return NS_ERROR_OUT_OF_MEMORY;
265 :
266 3 : SET_JSID_TO_STRING(sConstructor_id, cx, "constructor");
267 3 : SET_JSID_TO_STRING(sWrappedJSObject_id, cx, "wrappedJSObject");
268 :
269 3 : return NS_OK;
270 : }
271 :
272 : // static
273 : bool
274 2 : nsDOMClassInfo::ObjectIsNativeWrapper(JSContext* cx, JSObject* obj)
275 : {
276 2 : return xpc::WrapperFactory::IsXrayWrapper(obj) &&
277 2 : xpc::AccessCheck::wrapperSubsumes(obj);
278 : }
279 :
280 8 : nsDOMClassInfo::nsDOMClassInfo(nsDOMClassInfoData* aData) : mData(aData)
281 : {
282 8 : }
283 :
284 5981 : NS_IMPL_ADDREF(nsDOMClassInfo)
285 5832 : NS_IMPL_RELEASE(nsDOMClassInfo)
286 :
287 3065 : NS_INTERFACE_MAP_BEGIN(nsDOMClassInfo)
288 3065 : if (aIID.Equals(NS_GET_IID(nsXPCClassInfo)))
289 57 : foundInterface = static_cast<nsIClassInfo*>(
290 : static_cast<nsXPCClassInfo*>(this));
291 : else
292 3008 : NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable)
293 90 : NS_INTERFACE_MAP_ENTRY(nsIClassInfo)
294 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIClassInfo)
295 0 : NS_INTERFACE_MAP_END
296 :
297 :
298 : static const JSClass sDOMConstructorProtoClass = {
299 : "DOM Constructor.prototype", 0
300 : };
301 :
302 :
303 : static const char *
304 30 : CutPrefix(const char *aName) {
305 : static const char prefix_nsIDOM[] = "nsIDOM";
306 : static const char prefix_nsI[] = "nsI";
307 :
308 30 : if (strncmp(aName, prefix_nsIDOM, sizeof(prefix_nsIDOM) - 1) == 0) {
309 30 : return aName + sizeof(prefix_nsIDOM) - 1;
310 : }
311 :
312 0 : if (strncmp(aName, prefix_nsI, sizeof(prefix_nsI) - 1) == 0) {
313 0 : return aName + sizeof(prefix_nsI) - 1;
314 : }
315 :
316 0 : return aName;
317 : }
318 :
319 : // static
320 : nsresult
321 33 : nsDOMClassInfo::RegisterClassProtos(int32_t aClassInfoID)
322 : {
323 33 : nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
324 33 : NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
325 : bool found_old;
326 :
327 33 : const nsIID *primary_iid = sClassInfoData[aClassInfoID].mProtoChainInterface;
328 :
329 33 : if (!primary_iid || primary_iid == &NS_GET_IID(nsISupports)) {
330 12 : return NS_OK;
331 : }
332 :
333 : nsCOMPtr<nsIInterfaceInfoManager>
334 42 : iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
335 21 : NS_ENSURE_TRUE(iim, NS_ERROR_NOT_AVAILABLE);
336 :
337 42 : nsCOMPtr<nsIInterfaceInfo> if_info;
338 21 : bool first = true;
339 :
340 21 : iim->GetInfoForIID(primary_iid, getter_AddRefs(if_info));
341 :
342 63 : while (if_info) {
343 42 : const nsIID *iid = nullptr;
344 :
345 42 : if_info->GetIIDShared(&iid);
346 42 : NS_ENSURE_TRUE(iid, NS_ERROR_UNEXPECTED);
347 :
348 42 : if (iid->Equals(NS_GET_IID(nsISupports))) {
349 33 : break;
350 : }
351 :
352 30 : const char *name = nullptr;
353 30 : if_info->GetNameShared(&name);
354 30 : NS_ENSURE_TRUE(name, NS_ERROR_UNEXPECTED);
355 :
356 30 : nameSpaceManager->RegisterClassProto(CutPrefix(name), iid, &found_old);
357 :
358 30 : if (first) {
359 21 : first = false;
360 9 : } else if (found_old) {
361 9 : break;
362 : }
363 :
364 42 : nsCOMPtr<nsIInterfaceInfo> tmp(if_info);
365 21 : tmp->GetParent(getter_AddRefs(if_info));
366 : }
367 :
368 21 : return NS_OK;
369 : }
370 :
371 : #define _DOM_CLASSINFO_MAP_BEGIN(_class, _ifptr, _has_class_if) \
372 : { \
373 : nsDOMClassInfoData &d = sClassInfoData[eDOMClassInfo_##_class##_id]; \
374 : d.mProtoChainInterface = _ifptr; \
375 : d.mHasClassInterface = _has_class_if; \
376 : static const nsIID *interface_list[] = {
377 :
378 : #define DOM_CLASSINFO_MAP_BEGIN(_class, _interface) \
379 : _DOM_CLASSINFO_MAP_BEGIN(_class, &NS_GET_IID(_interface), true)
380 :
381 : #define DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(_class, _interface) \
382 : _DOM_CLASSINFO_MAP_BEGIN(_class, &NS_GET_IID(_interface), false)
383 :
384 : #define DOM_CLASSINFO_MAP_ENTRY(_if) \
385 : &NS_GET_IID(_if),
386 :
387 : #define DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(_if, _cond) \
388 : (_cond) ? &NS_GET_IID(_if) : nullptr,
389 :
390 : #define DOM_CLASSINFO_MAP_END \
391 : nullptr \
392 : }; \
393 : \
394 : /* Compact the interface list */ \
395 : size_t count = ArrayLength(interface_list); \
396 : /* count is the number of array entries, which is one greater than the */ \
397 : /* number of interfaces due to the terminating null */ \
398 : for (size_t i = 0; i < count - 1; ++i) { \
399 : if (!interface_list[i]) { \
400 : /* We are moving the element at index i+1 and successors, */ \
401 : /* so we must move only count - (i+1) elements total. */ \
402 : memmove(&interface_list[i], &interface_list[i+1], \
403 : sizeof(nsIID*) * (count - (i+1))); \
404 : /* Make sure to examine the new pointer we ended up with at this */ \
405 : /* slot, since it may be null too */ \
406 : --i; \
407 : --count; \
408 : } \
409 : } \
410 : \
411 : d.mInterfaces = interface_list; \
412 : }
413 :
414 : nsresult
415 3 : nsDOMClassInfo::Init()
416 : {
417 : /* Errors that can trigger early returns are done first,
418 : otherwise nsDOMClassInfo is left in a half inited state. */
419 : static_assert(sizeof(uintptr_t) == sizeof(void*),
420 : "BAD! You'll need to adjust the size of uintptr_t to the "
421 : "size of a pointer on your platform.");
422 :
423 3 : NS_ENSURE_TRUE(!sIsInitialized, NS_ERROR_ALREADY_INITIALIZED);
424 :
425 3 : nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
426 3 : NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
427 :
428 3 : NS_ADDREF(sXPConnect = nsContentUtils::XPConnect());
429 :
430 6 : nsCOMPtr<nsIXPCFunctionThisTranslator> elt = new nsEventListenerThisTranslator();
431 3 : sXPConnect->SetFunctionThisTranslator(NS_GET_IID(nsIDOMEventListener), elt);
432 :
433 3 : DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(DOMPrototype, nsIDOMDOMConstructor)
434 : DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMConstructor)
435 3 : DOM_CLASSINFO_MAP_END
436 :
437 3 : DOM_CLASSINFO_MAP_BEGIN(DOMConstructor, nsIDOMDOMConstructor)
438 : DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMConstructor)
439 3 : DOM_CLASSINFO_MAP_END
440 :
441 3 : DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ContentFrameMessageManager, nsISupports)
442 : DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
443 : DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager)
444 : DOM_CLASSINFO_MAP_ENTRY(nsIMessageSender)
445 : DOM_CLASSINFO_MAP_ENTRY(nsISyncMessageSender)
446 : DOM_CLASSINFO_MAP_ENTRY(nsIContentFrameMessageManager)
447 3 : DOM_CLASSINFO_MAP_END
448 :
449 3 : DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ContentProcessMessageManager, nsISupports)
450 : DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager)
451 : DOM_CLASSINFO_MAP_ENTRY(nsIMessageSender)
452 : DOM_CLASSINFO_MAP_ENTRY(nsISyncMessageSender)
453 : DOM_CLASSINFO_MAP_ENTRY(nsIContentProcessMessageManager)
454 3 : DOM_CLASSINFO_MAP_END
455 :
456 3 : DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ChromeMessageBroadcaster, nsISupports)
457 : DOM_CLASSINFO_MAP_ENTRY(nsIFrameScriptLoader)
458 : DOM_CLASSINFO_MAP_ENTRY(nsIProcessScriptLoader)
459 : DOM_CLASSINFO_MAP_ENTRY(nsIGlobalProcessScriptLoader)
460 : DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager)
461 : DOM_CLASSINFO_MAP_ENTRY(nsIMessageBroadcaster)
462 3 : DOM_CLASSINFO_MAP_END
463 :
464 3 : DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ChromeMessageSender, nsISupports)
465 : DOM_CLASSINFO_MAP_ENTRY(nsIFrameScriptLoader)
466 : DOM_CLASSINFO_MAP_ENTRY(nsIProcessScriptLoader)
467 : DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager)
468 : DOM_CLASSINFO_MAP_ENTRY(nsIMessageSender)
469 3 : DOM_CLASSINFO_MAP_END
470 :
471 3 : DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULControlElement, nsIDOMXULControlElement)
472 : DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULControlElement)
473 3 : DOM_CLASSINFO_MAP_END
474 :
475 3 : DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULLabeledControlElement, nsIDOMXULLabeledControlElement)
476 : DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULLabeledControlElement)
477 3 : DOM_CLASSINFO_MAP_END
478 :
479 3 : DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULButtonElement, nsIDOMXULButtonElement)
480 : DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULButtonElement)
481 3 : DOM_CLASSINFO_MAP_END
482 :
483 3 : DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULCheckboxElement, nsIDOMXULCheckboxElement)
484 : DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULCheckboxElement)
485 3 : DOM_CLASSINFO_MAP_END
486 :
487 3 : DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULPopupElement, nsIDOMXULPopupElement)
488 : DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULPopupElement)
489 3 : DOM_CLASSINFO_MAP_END
490 :
491 : static_assert(MOZ_ARRAY_LENGTH(sClassInfoData) == eDOMClassInfoIDCount,
492 : "The number of items in sClassInfoData doesn't match the "
493 : "number of nsIDOMClassInfo ID's, this is bad! Fix it!");
494 :
495 : #ifdef DEBUG
496 36 : for (size_t i = 0; i < eDOMClassInfoIDCount; i++) {
497 66 : if (!sClassInfoData[i].mConstructorFptr ||
498 33 : sClassInfoData[i].mDebugID != i) {
499 0 : MOZ_CRASH("Class info data out of sync, you forgot to update "
500 : "nsDOMClassInfo.h and nsDOMClassInfo.cpp! Fix this, "
501 : "mozilla will not work without this fixed!");
502 : }
503 : }
504 :
505 36 : for (size_t i = 0; i < eDOMClassInfoIDCount; i++) {
506 33 : if (!sClassInfoData[i].mInterfaces) {
507 0 : MOZ_CRASH("Class info data without an interface list! Fix this, "
508 : "mozilla will not work without this fixed!");
509 : }
510 : }
511 : #endif
512 :
513 : // Initialize static JSString's
514 3 : DefineStaticJSVals();
515 :
516 : int32_t i;
517 :
518 36 : for (i = 0; i < eDOMClassInfoIDCount; ++i) {
519 33 : if (i == eDOMClassInfo_DOMPrototype_id) {
520 3 : continue;
521 : }
522 :
523 30 : nsDOMClassInfoData& data = sClassInfoData[i];
524 60 : nameSpaceManager->RegisterClassName(data.mClass.name, i, data.mChromeOnly,
525 60 : data.mAllowXBL, &data.mNameUTF16);
526 : }
527 :
528 36 : for (i = 0; i < eDOMClassInfoIDCount; ++i) {
529 33 : RegisterClassProtos(i);
530 : }
531 :
532 3 : sIsInitialized = true;
533 :
534 3 : return NS_OK;
535 : }
536 :
537 : NS_IMETHODIMP
538 8 : nsDOMClassInfo::GetInterfaces(uint32_t *aCount, nsIID ***aArray)
539 : {
540 8 : uint32_t count = 0;
541 :
542 72 : while (mData->mInterfaces[count]) {
543 32 : count++;
544 : }
545 :
546 8 : *aCount = count;
547 :
548 8 : if (!count) {
549 0 : *aArray = nullptr;
550 :
551 0 : return NS_OK;
552 : }
553 :
554 8 : *aArray = static_cast<nsIID **>(moz_xmalloc(count * sizeof(nsIID *)));
555 8 : NS_ENSURE_TRUE(*aArray, NS_ERROR_OUT_OF_MEMORY);
556 :
557 : uint32_t i;
558 40 : for (i = 0; i < count; i++) {
559 32 : nsIID *iid = static_cast<nsIID *>(nsMemory::Clone(mData->mInterfaces[i],
560 32 : sizeof(nsIID)));
561 :
562 32 : if (!iid) {
563 0 : NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, *aArray);
564 :
565 0 : return NS_ERROR_OUT_OF_MEMORY;
566 : }
567 :
568 32 : *((*aArray) + i) = iid;
569 : }
570 :
571 8 : return NS_OK;
572 : }
573 :
574 : NS_IMETHODIMP
575 0 : nsDOMClassInfo::GetScriptableHelper(nsIXPCScriptable **_retval)
576 : {
577 0 : nsCOMPtr<nsIXPCScriptable> rval = this;
578 0 : rval.forget(_retval);
579 0 : return NS_OK;
580 : }
581 :
582 : NS_IMETHODIMP
583 0 : nsDOMClassInfo::GetContractID(char **aContractID)
584 : {
585 0 : *aContractID = nullptr;
586 :
587 0 : return NS_OK;
588 : }
589 :
590 : NS_IMETHODIMP
591 0 : nsDOMClassInfo::GetClassDescription(char **aClassDescription)
592 : {
593 0 : return GetClassName(aClassDescription);
594 : }
595 :
596 : NS_IMETHODIMP
597 0 : nsDOMClassInfo::GetClassID(nsCID **aClassID)
598 : {
599 0 : *aClassID = nullptr;
600 0 : return NS_OK;
601 : }
602 :
603 : NS_IMETHODIMP
604 0 : nsDOMClassInfo::GetClassIDNoAlloc(nsCID *aClassID)
605 : {
606 0 : return NS_ERROR_NOT_AVAILABLE;
607 : }
608 :
609 : NS_IMETHODIMP
610 180 : nsDOMClassInfo::GetFlags(uint32_t *aFlags)
611 : {
612 180 : *aFlags = DOMCLASSINFO_STANDARD_FLAGS;
613 :
614 180 : return NS_OK;
615 : }
616 :
617 : // nsIXPCScriptable
618 :
619 : NS_IMETHODIMP
620 0 : nsDOMClassInfo::GetClassName(char **aClassName)
621 : {
622 0 : *aClassName = NS_strdup(mData->mClass.name);
623 :
624 0 : return NS_OK;
625 : }
626 :
627 : // virtual
628 : uint32_t
629 2180 : nsDOMClassInfo::GetScriptableFlags()
630 : {
631 2180 : return mData->mScriptableFlags;
632 : }
633 :
634 : // virtual
635 : const js::Class*
636 0 : nsDOMClassInfo::GetClass()
637 : {
638 0 : return &mData->mClass;
639 : }
640 :
641 : // virtual
642 : const JSClass*
643 57 : nsDOMClassInfo::GetJSClass()
644 : {
645 57 : return Jsvalify(&mData->mClass);
646 : }
647 :
648 : NS_IMETHODIMP
649 270 : nsDOMClassInfo::PreCreate(nsISupports *nativeObj, JSContext *cx,
650 : JSObject *globalObj, JSObject **parentObj)
651 : {
652 270 : *parentObj = globalObj;
653 270 : return NS_OK;
654 : }
655 :
656 : NS_IMETHODIMP
657 0 : nsDOMClassInfo::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
658 : JSObject *obj, jsid id, JS::Value *vp,
659 : bool *_retval)
660 : {
661 0 : NS_WARNING("nsDOMClassInfo::GetProperty Don't call me!");
662 :
663 0 : return NS_OK;
664 : }
665 :
666 : NS_IMETHODIMP
667 0 : nsDOMClassInfo::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
668 : JSObject *obj, jsid id, JS::Value *vp,
669 : bool *_retval)
670 : {
671 0 : NS_WARNING("nsDOMClassInfo::SetProperty Don't call me!");
672 :
673 0 : return NS_ERROR_UNEXPECTED;
674 : }
675 :
676 : NS_IMETHODIMP
677 0 : nsDOMClassInfo::Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
678 : JSObject *obj, bool *_retval)
679 : {
680 0 : return NS_OK;
681 : }
682 :
683 : NS_IMETHODIMP
684 0 : nsDOMClassInfo::NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
685 : JSObject *obj, JS::AutoIdVector &properties,
686 : bool *_retval)
687 : {
688 0 : NS_WARNING("nsDOMClassInfo::NewEnumerate Don't call me!");
689 :
690 0 : return NS_ERROR_UNEXPECTED;
691 : }
692 :
693 : NS_IMETHODIMP
694 823 : nsDOMClassInfo::Resolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
695 : JSObject *aObj, jsid aId, bool *resolvedp, bool *_retval)
696 : {
697 1646 : JS::Rooted<JSObject*> obj(cx, aObj);
698 1646 : JS::Rooted<jsid> id(cx, aId);
699 :
700 823 : if (id != sConstructor_id) {
701 823 : *resolvedp = false;
702 823 : return NS_OK;
703 : }
704 :
705 0 : JS::Rooted<JSObject*> global(cx, ::JS_GetGlobalForObject(cx, obj));
706 :
707 0 : JS::Rooted<JS::PropertyDescriptor> desc(cx);
708 0 : if (!JS_GetPropertyDescriptor(cx, global, mData->mClass.name, &desc)) {
709 0 : return NS_ERROR_UNEXPECTED;
710 : }
711 :
712 0 : if (desc.object() && !desc.hasGetterOrSetter() && desc.value().isObject()) {
713 : // If val is not an (non-null) object there either is no
714 : // constructor for this class, or someone messed with
715 : // window.classname, just fall through and let the JS engine
716 : // return the Object constructor.
717 0 : if (!::JS_DefinePropertyById(cx, obj, id, desc.value(),
718 : JSPROP_ENUMERATE,
719 : JS_STUBGETTER, JS_STUBSETTER)) {
720 0 : return NS_ERROR_UNEXPECTED;
721 : }
722 :
723 0 : *resolvedp = true;
724 : }
725 :
726 0 : return NS_OK;
727 : }
728 :
729 : NS_IMETHODIMP
730 0 : nsDOMClassInfo::Finalize(nsIXPConnectWrappedNative *wrapper, JSFreeOp *fop,
731 : JSObject *obj)
732 : {
733 0 : NS_WARNING("nsDOMClassInfo::Finalize Don't call me!");
734 :
735 0 : return NS_ERROR_UNEXPECTED;
736 : }
737 :
738 : NS_IMETHODIMP
739 0 : nsDOMClassInfo::Call(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
740 : JSObject *obj, const JS::CallArgs &args, bool *_retval)
741 : {
742 0 : NS_WARNING("nsDOMClassInfo::Call Don't call me!");
743 :
744 0 : return NS_ERROR_UNEXPECTED;
745 : }
746 :
747 : NS_IMETHODIMP
748 0 : nsDOMClassInfo::Construct(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
749 : JSObject *obj, const JS::CallArgs &args,
750 : bool *_retval)
751 : {
752 0 : NS_WARNING("nsDOMClassInfo::Construct Don't call me!");
753 :
754 0 : return NS_ERROR_UNEXPECTED;
755 : }
756 :
757 : NS_IMETHODIMP
758 0 : nsDOMClassInfo::HasInstance(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
759 : JSObject *obj, JS::Handle<JS::Value> val, bool *bp,
760 : bool *_retval)
761 : {
762 0 : NS_WARNING("nsDOMClassInfo::HasInstance Don't call me!");
763 :
764 0 : return NS_ERROR_UNEXPECTED;
765 : }
766 :
767 : static nsresult
768 : ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx,
769 : JS::Handle<JSObject*> obj, const char16_t *name,
770 : const nsDOMClassInfoData *ci_data,
771 : const nsGlobalNameStruct *name_struct,
772 : nsScriptNameSpaceManager *nameSpaceManager,
773 : JSObject *dot_prototype,
774 : JS::MutableHandle<JS::PropertyDescriptor> ctorDesc);
775 :
776 : NS_IMETHODIMP
777 36 : nsDOMClassInfo::PostCreatePrototype(JSContext * cx, JSObject * aProto)
778 : {
779 72 : JS::Rooted<JSObject*> proto(cx, aProto);
780 :
781 : // This is called before any other location that requires
782 : // sObjectClass, so compute it here. We assume that nobody has had a
783 : // chance to monkey around with proto's prototype chain before this.
784 36 : if (!sObjectClass) {
785 1 : FindObjectClass(cx, proto);
786 1 : NS_ASSERTION(sObjectClass && !strcmp(sObjectClass->name, "Object"),
787 : "Incorrect object class!");
788 : }
789 :
790 : #ifdef DEBUG
791 72 : JS::Rooted<JSObject*> proto2(cx);
792 36 : JS_GetPrototype(cx, proto, &proto2);
793 36 : NS_ASSERTION(proto2 && JS_GetClass(proto2) == sObjectClass,
794 : "Hmm, somebody did something evil?");
795 : #endif
796 :
797 : #ifdef DEBUG
798 36 : if (mData->mHasClassInterface && mData->mProtoChainInterface &&
799 0 : mData->mProtoChainInterface != &NS_GET_IID(nsISupports)) {
800 : nsCOMPtr<nsIInterfaceInfoManager>
801 0 : iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
802 :
803 0 : if (iim) {
804 0 : nsCOMPtr<nsIInterfaceInfo> if_info;
805 0 : iim->GetInfoForIID(mData->mProtoChainInterface,
806 0 : getter_AddRefs(if_info));
807 :
808 0 : if (if_info) {
809 0 : nsXPIDLCString name;
810 0 : if_info->GetName(getter_Copies(name));
811 0 : NS_ASSERTION(nsCRT::strcmp(CutPrefix(name), mData->mClass.name) == 0,
812 : "Class name and proto chain interface name mismatch!");
813 : }
814 : }
815 : }
816 : #endif
817 :
818 : // Make prototype delegation work correctly. Consider if a site sets
819 : // HTMLElement.prototype.foopy = function () { ... } Now, calling
820 : // document.body.foopy() needs to ensure that looking up foopy on
821 : // document.body's prototype will find the right function.
822 72 : JS::Rooted<JSObject*> global(cx, ::JS_GetGlobalForObject(cx, proto));
823 :
824 : // Only do this if the global object is a window.
825 : nsGlobalWindow* win;
826 36 : if (NS_FAILED(UNWRAP_OBJECT(Window, &global, win))) {
827 : // Not a window.
828 34 : return NS_OK;
829 : }
830 :
831 2 : if (win->IsClosedOrClosing()) {
832 0 : return NS_OK;
833 : }
834 :
835 : // Don't overwrite a property set by content.
836 : bool contentDefinedProperty;
837 2 : if (!::JS_AlreadyHasOwnUCProperty(cx, global, reinterpret_cast<const char16_t*>(mData->mNameUTF16),
838 2 : NS_strlen(mData->mNameUTF16),
839 : &contentDefinedProperty)) {
840 0 : return NS_ERROR_FAILURE;
841 : }
842 :
843 2 : nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
844 2 : NS_ENSURE_TRUE(nameSpaceManager, NS_OK);
845 :
846 4 : JS::Rooted<JS::PropertyDescriptor> desc(cx);
847 6 : nsresult rv = ResolvePrototype(sXPConnect, win, cx, global, mData->mNameUTF16,
848 : mData, nullptr, nameSpaceManager, proto,
849 4 : &desc);
850 2 : NS_ENSURE_SUCCESS(rv, rv);
851 2 : if (!contentDefinedProperty && desc.object() && !desc.value().isUndefined()) {
852 2 : desc.attributesRef() |= JSPROP_RESOLVING;
853 4 : if (!JS_DefineUCProperty(cx, global, mData->mNameUTF16,
854 2 : NS_strlen(mData->mNameUTF16), desc)) {
855 0 : return NS_ERROR_UNEXPECTED;
856 : }
857 : }
858 :
859 2 : return NS_OK;
860 : }
861 :
862 : // static
863 : nsIClassInfo *
864 57 : NS_GetDOMClassInfoInstance(nsDOMClassInfoID aID)
865 : {
866 57 : if (aID >= eDOMClassInfoIDCount) {
867 0 : NS_ERROR("Bad ID!");
868 :
869 0 : return nullptr;
870 : }
871 :
872 57 : nsresult rv = RegisterDOMNames();
873 57 : NS_ENSURE_SUCCESS(rv, nullptr);
874 :
875 57 : if (!sClassInfoData[aID].mCachedClassInfo) {
876 8 : nsDOMClassInfoData& data = sClassInfoData[aID];
877 :
878 8 : data.mCachedClassInfo = data.mConstructorFptr(&data);
879 8 : NS_ENSURE_TRUE(data.mCachedClassInfo, nullptr);
880 :
881 8 : NS_ADDREF(data.mCachedClassInfo);
882 : }
883 :
884 57 : return sClassInfoData[aID].mCachedClassInfo;
885 : }
886 :
887 : // static
888 : void
889 0 : nsDOMClassInfo::ShutDown()
890 : {
891 0 : if (sClassInfoData[0].mConstructorFptr) {
892 : uint32_t i;
893 :
894 0 : for (i = 0; i < eDOMClassInfoIDCount; i++) {
895 0 : NS_IF_RELEASE(sClassInfoData[i].mCachedClassInfo);
896 : }
897 : }
898 :
899 0 : sConstructor_id = JSID_VOID;
900 0 : sWrappedJSObject_id = JSID_VOID;
901 :
902 0 : NS_IF_RELEASE(sXPConnect);
903 0 : sIsInitialized = false;
904 0 : }
905 :
906 : static nsresult
907 0 : BaseStubConstructor(nsIWeakReference* aWeakOwner,
908 : const nsGlobalNameStruct *name_struct, JSContext *cx,
909 : JS::Handle<JSObject*> obj, const JS::CallArgs &args)
910 : {
911 0 : MOZ_ASSERT(obj);
912 0 : MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
913 :
914 : nsresult rv;
915 0 : nsCOMPtr<nsISupports> native;
916 0 : if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
917 0 : rv = NS_ERROR_NOT_AVAILABLE;
918 : } else {
919 0 : MOZ_ASSERT(name_struct->mType ==
920 : nsGlobalNameStruct::eTypeExternalConstructor);
921 0 : native = do_CreateInstance(name_struct->mCID, &rv);
922 : }
923 0 : if (NS_FAILED(rv)) {
924 0 : NS_ERROR("Failed to create the object");
925 0 : return rv;
926 : }
927 :
928 0 : js::AssertSameCompartment(cx, obj);
929 0 : return nsContentUtils::WrapNative(cx, native, args.rval(), true);
930 : }
931 :
932 : static nsresult
933 0 : DefineInterfaceConstants(JSContext *cx, JS::Handle<JSObject*> obj, const nsIID *aIID)
934 : {
935 : nsCOMPtr<nsIInterfaceInfoManager>
936 0 : iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
937 0 : NS_ENSURE_TRUE(iim, NS_ERROR_UNEXPECTED);
938 :
939 0 : nsCOMPtr<nsIInterfaceInfo> if_info;
940 :
941 0 : nsresult rv = iim->GetInfoForIID(aIID, getter_AddRefs(if_info));
942 0 : NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && if_info, rv);
943 :
944 : uint16_t constant_count;
945 :
946 0 : if_info->GetConstantCount(&constant_count);
947 :
948 0 : if (!constant_count) {
949 0 : return NS_OK;
950 : }
951 :
952 0 : nsCOMPtr<nsIInterfaceInfo> parent_if_info;
953 :
954 0 : rv = if_info->GetParent(getter_AddRefs(parent_if_info));
955 0 : NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && parent_if_info, rv);
956 :
957 : uint16_t parent_constant_count, i;
958 0 : parent_if_info->GetConstantCount(&parent_constant_count);
959 :
960 0 : JS::Rooted<JS::Value> v(cx);
961 0 : for (i = parent_constant_count; i < constant_count; i++) {
962 0 : nsXPIDLCString name;
963 0 : rv = if_info->GetConstant(i, &v, getter_Copies(name));
964 0 : NS_ENSURE_TRUE(NS_SUCCEEDED(rv), rv);
965 :
966 0 : if (!::JS_DefineProperty(cx, obj, name, v,
967 : JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT,
968 : JS_STUBGETTER, JS_STUBSETTER)) {
969 0 : return NS_ERROR_UNEXPECTED;
970 : }
971 : }
972 :
973 0 : return NS_OK;
974 : }
975 :
976 : class nsDOMConstructor final : public nsIDOMDOMConstructor
977 : {
978 : protected:
979 2 : nsDOMConstructor(const char16_t* aName,
980 : bool aIsConstructable,
981 : nsPIDOMWindowInner* aOwner)
982 2 : : mClassName(aName),
983 : mConstructable(aIsConstructable),
984 2 : mWeakOwner(do_GetWeakReference(aOwner))
985 : {
986 2 : }
987 :
988 0 : ~nsDOMConstructor() {}
989 :
990 : public:
991 :
992 : static nsresult Create(const char16_t* aName,
993 : const nsGlobalNameStruct* aNameStruct,
994 : nsPIDOMWindowInner* aOwner,
995 : nsDOMConstructor** aResult);
996 :
997 : NS_DECL_ISUPPORTS
998 : NS_DECL_NSIDOMDOMCONSTRUCTOR
999 :
1000 : nsresult PreCreate(JSContext *cx, JSObject *globalObj, JSObject **parentObj);
1001 :
1002 : nsresult Construct(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
1003 : JS::Handle<JSObject*> obj, const JS::CallArgs &args,
1004 : bool *_retval);
1005 :
1006 : nsresult HasInstance(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
1007 : JS::Handle<JSObject*> obj, const JS::Value &val, bool *bp,
1008 : bool *_retval);
1009 :
1010 : nsresult ResolveInterfaceConstants(JSContext *cx, JS::Handle<JSObject*> obj);
1011 :
1012 : private:
1013 2 : const nsGlobalNameStruct *GetNameStruct()
1014 : {
1015 2 : if (!mClassName) {
1016 0 : NS_ERROR("Can't get name");
1017 0 : return nullptr;
1018 : }
1019 :
1020 : const nsGlobalNameStruct *nameStruct;
1021 : #ifdef DEBUG
1022 : nsresult rv =
1023 : #endif
1024 2 : GetNameStruct(nsDependentString(mClassName), &nameStruct);
1025 :
1026 2 : NS_ASSERTION(NS_FAILED(rv) || nameStruct, "Name isn't in hash.");
1027 :
1028 2 : return nameStruct;
1029 : }
1030 :
1031 2 : static nsresult GetNameStruct(const nsAString& aName,
1032 : const nsGlobalNameStruct **aNameStruct)
1033 : {
1034 2 : *aNameStruct = nullptr;
1035 :
1036 2 : nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
1037 2 : if (!nameSpaceManager) {
1038 0 : NS_ERROR("Can't get namespace manager.");
1039 0 : return NS_ERROR_UNEXPECTED;
1040 : }
1041 :
1042 2 : *aNameStruct = nameSpaceManager->LookupName(aName);
1043 :
1044 : // Return NS_OK here, aName just isn't a DOM class but nothing failed.
1045 2 : return NS_OK;
1046 : }
1047 :
1048 2 : static bool IsConstructable(const nsGlobalNameStruct *aNameStruct)
1049 : {
1050 2 : return aNameStruct->mType == nsGlobalNameStruct::eTypeExternalConstructor;
1051 : }
1052 :
1053 : const char16_t* mClassName;
1054 : const bool mConstructable;
1055 : nsWeakPtr mWeakOwner;
1056 : };
1057 :
1058 : //static
1059 : nsresult
1060 2 : nsDOMConstructor::Create(const char16_t* aName,
1061 : const nsGlobalNameStruct* aNameStruct,
1062 : nsPIDOMWindowInner* aOwner,
1063 : nsDOMConstructor** aResult)
1064 : {
1065 2 : *aResult = nullptr;
1066 : // Prevent creating a constructor if aOwner is inner window which doesn't have
1067 : // an outer window. If the outer window doesn't have an inner window or the
1068 : // caller can't access the outer window's current inner window then try to use
1069 : // the owner (so long as it is, in fact, an inner window). If that doesn't
1070 : // work then prevent creation also.
1071 2 : nsPIDOMWindowOuter* outerWindow = aOwner->GetOuterWindow();
1072 : nsPIDOMWindowInner* currentInner =
1073 2 : outerWindow ? outerWindow->GetCurrentInnerWindow() : aOwner;
1074 2 : if (!currentInner ||
1075 0 : (aOwner != currentInner &&
1076 0 : !nsContentUtils::CanCallerAccess(currentInner) &&
1077 0 : !(currentInner = aOwner)->IsInnerWindow())) {
1078 0 : return NS_ERROR_DOM_SECURITY_ERR;
1079 : }
1080 :
1081 2 : bool constructable = aNameStruct && IsConstructable(aNameStruct);
1082 :
1083 2 : *aResult = new nsDOMConstructor(aName, constructable, currentInner);
1084 2 : NS_ADDREF(*aResult);
1085 2 : return NS_OK;
1086 : }
1087 :
1088 10 : NS_IMPL_ADDREF(nsDOMConstructor)
1089 6 : NS_IMPL_RELEASE(nsDOMConstructor)
1090 14 : NS_INTERFACE_MAP_BEGIN(nsDOMConstructor)
1091 14 : NS_INTERFACE_MAP_ENTRY(nsIDOMDOMConstructor)
1092 10 : NS_INTERFACE_MAP_ENTRY(nsISupports)
1093 8 : if (aIID.Equals(NS_GET_IID(nsIClassInfo))) {
1094 : #ifdef DEBUG
1095 : {
1096 2 : const nsGlobalNameStruct *name_struct = GetNameStruct();
1097 2 : NS_ASSERTION(!name_struct ||
1098 : mConstructable == IsConstructable(name_struct),
1099 : "Can't change constructability dynamically!");
1100 : }
1101 : #endif
1102 : foundInterface =
1103 2 : NS_GetDOMClassInfoInstance(mConstructable ?
1104 : eDOMClassInfo_DOMConstructor_id :
1105 2 : eDOMClassInfo_DOMPrototype_id);
1106 2 : if (!foundInterface) {
1107 0 : *aInstancePtr = nullptr;
1108 0 : return NS_ERROR_OUT_OF_MEMORY;
1109 : }
1110 : } else
1111 6 : NS_INTERFACE_MAP_END
1112 :
1113 : nsresult
1114 2 : nsDOMConstructor::PreCreate(JSContext *cx, JSObject *globalObj, JSObject **parentObj)
1115 : {
1116 4 : nsCOMPtr<nsPIDOMWindowInner> owner(do_QueryReferent(mWeakOwner));
1117 2 : if (!owner) {
1118 : // Can't do anything.
1119 0 : return NS_OK;
1120 : }
1121 :
1122 2 : nsGlobalWindow *win = nsGlobalWindow::Cast(owner);
1123 2 : return SetParentToWindow(win, parentObj);
1124 : }
1125 :
1126 : nsresult
1127 0 : nsDOMConstructor::Construct(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
1128 : JS::Handle<JSObject*> obj, const JS::CallArgs &args,
1129 : bool *_retval)
1130 : {
1131 0 : MOZ_ASSERT(obj);
1132 :
1133 0 : const nsGlobalNameStruct *name_struct = GetNameStruct();
1134 0 : NS_ENSURE_TRUE(name_struct, NS_ERROR_FAILURE);
1135 :
1136 0 : if (!IsConstructable(name_struct)) {
1137 : // ignore return value, we return false anyway
1138 0 : return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
1139 : }
1140 :
1141 0 : return BaseStubConstructor(mWeakOwner, name_struct, cx, obj, args);
1142 : }
1143 :
1144 : nsresult
1145 0 : nsDOMConstructor::HasInstance(nsIXPConnectWrappedNative *wrapper,
1146 : JSContext * cx, JS::Handle<JSObject*> obj,
1147 : const JS::Value &v, bool *bp, bool *_retval)
1148 :
1149 : {
1150 : // No need to look these up in the hash.
1151 0 : *bp = false;
1152 0 : if (v.isPrimitive()) {
1153 0 : return NS_OK;
1154 : }
1155 :
1156 0 : JS::Rooted<JSObject*> dom_obj(cx, v.toObjectOrNull());
1157 0 : NS_ASSERTION(dom_obj, "nsDOMConstructor::HasInstance couldn't get object");
1158 :
1159 : // This might not be the right object, if there are wrappers. Unwrap if we can.
1160 0 : JSObject *wrapped_obj = js::CheckedUnwrap(dom_obj, /* stopAtWindowProxy = */ false);
1161 0 : if (wrapped_obj)
1162 0 : dom_obj = wrapped_obj;
1163 :
1164 0 : const JSClass *dom_class = JS_GetClass(dom_obj);
1165 0 : if (!dom_class) {
1166 0 : NS_ERROR("nsDOMConstructor::HasInstance can't get class.");
1167 0 : return NS_ERROR_UNEXPECTED;
1168 : }
1169 :
1170 : const nsGlobalNameStruct *name_struct;
1171 0 : nsresult rv = GetNameStruct(NS_ConvertASCIItoUTF16(dom_class->name), &name_struct);
1172 0 : if (NS_FAILED(rv)) {
1173 0 : return rv;
1174 : }
1175 :
1176 0 : if (!name_struct) {
1177 : // This isn't a normal DOM object, see if this constructor lives on its
1178 : // prototype chain.
1179 0 : JS::Rooted<JS::PropertyDescriptor> desc(cx);
1180 0 : if (!JS_GetPropertyDescriptor(cx, obj, "prototype", &desc)) {
1181 0 : return NS_ERROR_UNEXPECTED;
1182 : }
1183 :
1184 0 : if (!desc.object() || desc.hasGetterOrSetter() || !desc.value().isObject()) {
1185 0 : return NS_OK;
1186 : }
1187 :
1188 0 : JS::Rooted<JSObject*> dot_prototype(cx, &desc.value().toObject());
1189 :
1190 0 : JS::Rooted<JSObject*> proto(cx, dom_obj);
1191 0 : JSAutoCompartment ac(cx, proto);
1192 :
1193 0 : if (!JS_WrapObject(cx, &dot_prototype)) {
1194 0 : return NS_ERROR_UNEXPECTED;
1195 : }
1196 :
1197 : for (;;) {
1198 0 : if (!JS_GetPrototype(cx, proto, &proto)) {
1199 0 : return NS_ERROR_UNEXPECTED;
1200 : }
1201 0 : if (!proto) {
1202 0 : break;
1203 : }
1204 0 : if (proto == dot_prototype) {
1205 0 : *bp = true;
1206 0 : break;
1207 : }
1208 : }
1209 :
1210 0 : return NS_OK;
1211 : }
1212 :
1213 0 : if (name_struct->mType != nsGlobalNameStruct::eTypeClassConstructor) {
1214 : // Doesn't have DOM interfaces.
1215 0 : return NS_OK;
1216 : }
1217 :
1218 0 : const nsGlobalNameStruct *class_name_struct = GetNameStruct();
1219 0 : NS_ENSURE_TRUE(class_name_struct, NS_ERROR_FAILURE);
1220 :
1221 0 : if (name_struct == class_name_struct) {
1222 0 : *bp = true;
1223 :
1224 0 : return NS_OK;
1225 : }
1226 :
1227 : const nsIID *class_iid;
1228 0 : if (class_name_struct->mType == nsGlobalNameStruct::eTypeClassProto) {
1229 0 : class_iid = &class_name_struct->mIID;
1230 0 : } else if (class_name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
1231 0 : class_iid =
1232 0 : sClassInfoData[class_name_struct->mDOMClassInfoID].mProtoChainInterface;
1233 : } else {
1234 0 : *bp = false;
1235 :
1236 0 : return NS_OK;
1237 : }
1238 :
1239 0 : NS_ASSERTION(name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor,
1240 : "The constructor was set up with a struct of the wrong type.");
1241 :
1242 : const nsDOMClassInfoData *ci_data;
1243 0 : if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor &&
1244 0 : name_struct->mDOMClassInfoID >= 0) {
1245 0 : ci_data = &sClassInfoData[name_struct->mDOMClassInfoID];
1246 : } else {
1247 0 : ci_data = nullptr;
1248 : }
1249 :
1250 : nsCOMPtr<nsIInterfaceInfoManager>
1251 0 : iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
1252 0 : if (!iim) {
1253 0 : NS_ERROR("nsDOMConstructor::HasInstance can't get interface info mgr.");
1254 0 : return NS_ERROR_UNEXPECTED;
1255 : }
1256 :
1257 0 : nsCOMPtr<nsIInterfaceInfo> if_info;
1258 0 : uint32_t count = 0;
1259 : const nsIID* class_interface;
1260 0 : while ((class_interface = ci_data->mInterfaces[count++])) {
1261 0 : if (class_iid->Equals(*class_interface)) {
1262 0 : *bp = true;
1263 :
1264 0 : return NS_OK;
1265 : }
1266 :
1267 0 : iim->GetInfoForIID(class_interface, getter_AddRefs(if_info));
1268 0 : if (!if_info) {
1269 0 : NS_ERROR("nsDOMConstructor::HasInstance can't get interface info.");
1270 0 : return NS_ERROR_UNEXPECTED;
1271 : }
1272 :
1273 0 : if_info->HasAncestor(class_iid, bp);
1274 :
1275 0 : if (*bp) {
1276 0 : return NS_OK;
1277 : }
1278 : }
1279 :
1280 0 : return NS_OK;
1281 : }
1282 :
1283 : nsresult
1284 0 : nsDOMConstructor::ResolveInterfaceConstants(JSContext *cx, JS::Handle<JSObject*> obj)
1285 : {
1286 0 : const nsGlobalNameStruct *class_name_struct = GetNameStruct();
1287 0 : if (!class_name_struct)
1288 0 : return NS_ERROR_UNEXPECTED;
1289 :
1290 : const nsIID *class_iid;
1291 0 : if (class_name_struct->mType == nsGlobalNameStruct::eTypeClassProto) {
1292 0 : class_iid = &class_name_struct->mIID;
1293 0 : } else if (class_name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
1294 0 : class_iid =
1295 0 : sClassInfoData[class_name_struct->mDOMClassInfoID].mProtoChainInterface;
1296 : } else {
1297 0 : return NS_OK;
1298 : }
1299 :
1300 0 : nsresult rv = DefineInterfaceConstants(cx, obj, class_iid);
1301 0 : NS_ENSURE_SUCCESS(rv, rv);
1302 :
1303 0 : return NS_OK;
1304 : }
1305 :
1306 : NS_IMETHODIMP
1307 0 : nsDOMConstructor::ToString(nsAString &aResult)
1308 : {
1309 0 : aResult.AssignLiteral("[object ");
1310 0 : aResult.Append(mClassName);
1311 0 : aResult.Append(char16_t(']'));
1312 :
1313 0 : return NS_OK;
1314 : }
1315 :
1316 :
1317 : static nsresult
1318 0 : GetXPCProto(nsIXPConnect *aXPConnect, JSContext *cx, nsGlobalWindow *aWin,
1319 : const nsGlobalNameStruct *aNameStruct,
1320 : JS::MutableHandle<JSObject*> aProto)
1321 : {
1322 0 : NS_ASSERTION(aNameStruct->mType == nsGlobalNameStruct::eTypeClassConstructor,
1323 : "Wrong type!");
1324 :
1325 0 : int32_t id = aNameStruct->mDOMClassInfoID;
1326 0 : MOZ_ASSERT(id >= 0, "Negative DOM classinfo?!?");
1327 :
1328 0 : nsDOMClassInfoID ci_id = (nsDOMClassInfoID)id;
1329 :
1330 0 : nsCOMPtr<nsIClassInfo> ci = NS_GetDOMClassInfoInstance(ci_id);
1331 0 : NS_ENSURE_TRUE(ci, NS_ERROR_UNEXPECTED);
1332 :
1333 : nsresult rv =
1334 0 : aXPConnect->GetWrappedNativePrototype(cx, aWin->GetGlobalJSObject(), ci, aProto.address());
1335 0 : NS_ENSURE_SUCCESS(rv, rv);
1336 :
1337 0 : return JS_WrapObject(cx, aProto) ? NS_OK : NS_ERROR_FAILURE;
1338 : }
1339 :
1340 : // Either ci_data must be non-null or name_struct must be non-null and of type
1341 : // eTypeClassProto.
1342 : static nsresult
1343 2 : ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx,
1344 : JS::Handle<JSObject*> obj, const char16_t *name,
1345 : const nsDOMClassInfoData *ci_data,
1346 : const nsGlobalNameStruct *name_struct,
1347 : nsScriptNameSpaceManager *nameSpaceManager,
1348 : JSObject* aDot_prototype,
1349 : JS::MutableHandle<JS::PropertyDescriptor> ctorDesc)
1350 : {
1351 4 : JS::Rooted<JSObject*> dot_prototype(cx, aDot_prototype);
1352 2 : NS_ASSERTION(ci_data ||
1353 : (name_struct &&
1354 : name_struct->mType == nsGlobalNameStruct::eTypeClassProto),
1355 : "Wrong type or missing ci_data!");
1356 :
1357 4 : RefPtr<nsDOMConstructor> constructor;
1358 2 : nsresult rv = nsDOMConstructor::Create(name, name_struct, aWin->AsInner(),
1359 4 : getter_AddRefs(constructor));
1360 2 : NS_ENSURE_SUCCESS(rv, rv);
1361 :
1362 4 : JS::Rooted<JS::Value> v(cx);
1363 :
1364 2 : js::AssertSameCompartment(cx, obj);
1365 6 : rv = nsContentUtils::WrapNative(cx, constructor,
1366 : &NS_GET_IID(nsIDOMDOMConstructor), &v,
1367 4 : false);
1368 2 : NS_ENSURE_SUCCESS(rv, rv);
1369 :
1370 2 : FillPropertyDescriptor(ctorDesc, obj, 0, v);
1371 : // And make sure we wrap the value into the right compartment. Note that we
1372 : // do this with ctorDesc.value(), not with v, because we need v to be in the
1373 : // right compartment (that of the reflector of |constructor|) below.
1374 2 : if (!JS_WrapValue(cx, ctorDesc.value())) {
1375 0 : return NS_ERROR_UNEXPECTED;
1376 : }
1377 :
1378 4 : JS::Rooted<JSObject*> class_obj(cx, &v.toObject());
1379 :
1380 2 : const nsIID *primary_iid = &NS_GET_IID(nsISupports);
1381 :
1382 2 : if (!ci_data) {
1383 0 : primary_iid = &name_struct->mIID;
1384 : }
1385 2 : else if (ci_data->mProtoChainInterface) {
1386 2 : primary_iid = ci_data->mProtoChainInterface;
1387 : }
1388 :
1389 4 : nsCOMPtr<nsIInterfaceInfo> if_info;
1390 4 : nsCOMPtr<nsIInterfaceInfo> parent;
1391 2 : const char *class_parent_name = nullptr;
1392 :
1393 2 : if (!primary_iid->Equals(NS_GET_IID(nsISupports))) {
1394 0 : JSAutoCompartment ac(cx, class_obj);
1395 :
1396 0 : rv = DefineInterfaceConstants(cx, class_obj, primary_iid);
1397 0 : NS_ENSURE_SUCCESS(rv, rv);
1398 :
1399 : nsCOMPtr<nsIInterfaceInfoManager>
1400 0 : iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
1401 0 : NS_ENSURE_TRUE(iim, NS_ERROR_NOT_AVAILABLE);
1402 :
1403 0 : iim->GetInfoForIID(primary_iid, getter_AddRefs(if_info));
1404 0 : NS_ENSURE_TRUE(if_info, NS_ERROR_UNEXPECTED);
1405 :
1406 0 : const nsIID *iid = nullptr;
1407 :
1408 0 : if (ci_data && !ci_data->mHasClassInterface) {
1409 0 : if_info->GetIIDShared(&iid);
1410 : } else {
1411 0 : if_info->GetParent(getter_AddRefs(parent));
1412 0 : NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED);
1413 :
1414 0 : parent->GetIIDShared(&iid);
1415 : }
1416 :
1417 0 : if (iid) {
1418 0 : if (!iid->Equals(NS_GET_IID(nsISupports))) {
1419 0 : if (ci_data && !ci_data->mHasClassInterface) {
1420 : // If the class doesn't have a class interface the primary
1421 : // interface is the interface that should be
1422 : // constructor.prototype.__proto__.
1423 :
1424 0 : if_info->GetNameShared(&class_parent_name);
1425 : } else {
1426 : // If the class does have a class interface (or there's no
1427 : // real class for this name) then the parent of the
1428 : // primary interface is what we want on
1429 : // constructor.prototype.__proto__.
1430 :
1431 0 : NS_ASSERTION(parent, "Whoa, this is bad, null parent here!");
1432 :
1433 0 : parent->GetNameShared(&class_parent_name);
1434 : }
1435 : }
1436 : }
1437 : }
1438 :
1439 : {
1440 4 : JS::Rooted<JSObject*> winobj(cx, aWin->FastGetGlobalJSObject());
1441 :
1442 4 : JS::Rooted<JSObject*> proto(cx);
1443 :
1444 2 : if (class_parent_name) {
1445 0 : JSAutoCompartment ac(cx, winobj);
1446 :
1447 0 : JS::Rooted<JS::PropertyDescriptor> desc(cx);
1448 0 : if (!JS_GetPropertyDescriptor(cx, winobj, CutPrefix(class_parent_name), &desc)) {
1449 0 : return NS_ERROR_UNEXPECTED;
1450 : }
1451 :
1452 0 : if (desc.object() && !desc.hasGetterOrSetter() && desc.value().isObject()) {
1453 0 : JS::Rooted<JSObject*> obj(cx, &desc.value().toObject());
1454 0 : if (!JS_GetPropertyDescriptor(cx, obj, "prototype", &desc)) {
1455 0 : return NS_ERROR_UNEXPECTED;
1456 : }
1457 :
1458 0 : if (desc.object() && !desc.hasGetterOrSetter() && desc.value().isObject()) {
1459 0 : proto = &desc.value().toObject();
1460 : }
1461 : }
1462 : }
1463 :
1464 2 : if (dot_prototype) {
1465 4 : JSAutoCompartment ac(cx, dot_prototype);
1466 4 : JS::Rooted<JSObject*> xpc_proto_proto(cx);
1467 2 : if (!::JS_GetPrototype(cx, dot_prototype, &xpc_proto_proto)) {
1468 0 : return NS_ERROR_UNEXPECTED;
1469 : }
1470 :
1471 2 : if (proto &&
1472 0 : (!xpc_proto_proto ||
1473 2 : JS_GetClass(xpc_proto_proto) == sObjectClass)) {
1474 0 : if (!JS_WrapObject(cx, &proto) ||
1475 0 : !JS_SetPrototype(cx, dot_prototype, proto)) {
1476 0 : return NS_ERROR_UNEXPECTED;
1477 : }
1478 : }
1479 : } else {
1480 0 : JSAutoCompartment ac(cx, winobj);
1481 0 : if (!proto) {
1482 0 : proto = JS_GetObjectPrototype(cx, winobj);
1483 : }
1484 0 : dot_prototype = ::JS_NewObjectWithUniqueType(cx,
1485 : &sDOMConstructorProtoClass,
1486 0 : proto);
1487 0 : NS_ENSURE_TRUE(dot_prototype, NS_ERROR_OUT_OF_MEMORY);
1488 : }
1489 : }
1490 :
1491 2 : v.setObject(*dot_prototype);
1492 :
1493 4 : JSAutoCompartment ac(cx, class_obj);
1494 :
1495 : // Per ECMA, the prototype property is {DontEnum, DontDelete, ReadOnly}
1496 10 : if (!JS_WrapValue(cx, &v) ||
1497 8 : !JS_DefineProperty(cx, class_obj, "prototype", v,
1498 : JSPROP_PERMANENT | JSPROP_READONLY,
1499 : JS_STUBGETTER, JS_STUBSETTER)) {
1500 0 : return NS_ERROR_UNEXPECTED;
1501 : }
1502 :
1503 2 : return NS_OK;
1504 : }
1505 :
1506 : static bool
1507 0 : OldBindingConstructorEnabled(const nsGlobalNameStruct *aStruct,
1508 : nsGlobalWindow *aWin, JSContext *cx)
1509 : {
1510 0 : MOZ_ASSERT(aStruct->mType == nsGlobalNameStruct::eTypeProperty ||
1511 : aStruct->mType == nsGlobalNameStruct::eTypeClassConstructor);
1512 :
1513 : // Don't expose chrome only constructors to content windows.
1514 0 : if (aStruct->mChromeOnly) {
1515 : bool expose;
1516 0 : if (aStruct->mAllowXBL) {
1517 0 : expose = IsChromeOrXBL(cx, nullptr);
1518 : } else {
1519 0 : expose = nsContentUtils::IsSystemPrincipal(aWin->GetPrincipal());
1520 : }
1521 :
1522 0 : if (!expose) {
1523 0 : return false;
1524 : }
1525 : }
1526 :
1527 0 : return true;
1528 : }
1529 :
1530 : static nsresult
1531 : LookupComponentsShim(JSContext *cx, JS::Handle<JSObject*> global,
1532 : nsPIDOMWindowInner *win,
1533 : JS::MutableHandle<JS::PropertyDescriptor> desc);
1534 :
1535 : // static
1536 : bool
1537 0 : nsWindowSH::NameStructEnabled(JSContext* aCx, nsGlobalWindow *aWin,
1538 : const nsAString& aName,
1539 : const nsGlobalNameStruct& aNameStruct)
1540 : {
1541 : // DOMConstructor is special: creating its proto does not actually define it
1542 : // as a property on the global. So we don't want to expose its name either.
1543 0 : if (aName.EqualsLiteral("DOMConstructor")) {
1544 0 : return false;
1545 : }
1546 0 : const nsGlobalNameStruct* nameStruct = &aNameStruct;
1547 0 : return (nameStruct->mType != nsGlobalNameStruct::eTypeProperty &&
1548 0 : nameStruct->mType != nsGlobalNameStruct::eTypeClassConstructor) ||
1549 0 : OldBindingConstructorEnabled(nameStruct, aWin, aCx);
1550 : }
1551 :
1552 : #ifdef RELEASE_OR_BETA
1553 : #define USE_CONTROLLERS_SHIM
1554 : #endif
1555 :
1556 : #ifdef USE_CONTROLLERS_SHIM
1557 : static const JSClass ControllersShimClass = {
1558 : "Controllers", 0
1559 : };
1560 : static const JSClass XULControllersShimClass = {
1561 : "XULControllers", 0
1562 : };
1563 : #endif
1564 :
1565 : // static
1566 : nsresult
1567 3130 : nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
1568 : JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
1569 : JS::MutableHandle<JS::PropertyDescriptor> desc)
1570 : {
1571 3130 : if (id == XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_COMPONENTS)) {
1572 0 : return LookupComponentsShim(cx, obj, aWin->AsInner(), desc);
1573 : }
1574 :
1575 : #ifdef USE_CONTROLLERS_SHIM
1576 : // Note: We use |obj| rather than |aWin| to get the principal here, because
1577 : // this is called during Window setup when the Document isn't necessarily
1578 : // hooked up yet.
1579 : if ((id == XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_CONTROLLERS) ||
1580 : id == XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_CONTROLLERS_CLASS)) &&
1581 : !xpc::IsXrayWrapper(obj) &&
1582 : !nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(obj)))
1583 : {
1584 : if (aWin->GetDoc()) {
1585 : aWin->GetDoc()->WarnOnceAbout(nsIDocument::eWindow_Controllers);
1586 : }
1587 : const JSClass* clazz;
1588 : if (id == XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_CONTROLLERS)) {
1589 : clazz = &XULControllersShimClass;
1590 : } else {
1591 : clazz = &ControllersShimClass;
1592 : }
1593 : MOZ_ASSERT(JS_IsGlobalObject(obj));
1594 : JS::Rooted<JSObject*> shim(cx, JS_NewObject(cx, clazz));
1595 : if (NS_WARN_IF(!shim)) {
1596 : return NS_ERROR_OUT_OF_MEMORY;
1597 : }
1598 : FillPropertyDescriptor(desc, obj, JS::ObjectValue(*shim), /* readOnly = */ false);
1599 : return NS_OK;
1600 : }
1601 : #endif
1602 :
1603 3130 : nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
1604 3130 : NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
1605 :
1606 : // Note - Our only caller is nsGlobalWindow::DoResolve, which checks that
1607 : // JSID_IS_STRING(id) is true.
1608 6260 : nsAutoJSString name;
1609 3130 : if (!name.init(cx, JSID_TO_STRING(id))) {
1610 0 : return NS_ERROR_OUT_OF_MEMORY;
1611 : }
1612 :
1613 3130 : const char16_t *class_name = nullptr;
1614 : const nsGlobalNameStruct *name_struct =
1615 3130 : nameSpaceManager->LookupName(name, &class_name);
1616 :
1617 3130 : if (!name_struct) {
1618 3130 : return NS_OK;
1619 : }
1620 :
1621 : // The class_name had better match our name
1622 0 : MOZ_ASSERT(name.Equals(class_name));
1623 :
1624 0 : NS_ENSURE_TRUE(class_name, NS_ERROR_UNEXPECTED);
1625 :
1626 0 : nsresult rv = NS_OK;
1627 :
1628 0 : if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
1629 0 : if (!OldBindingConstructorEnabled(name_struct, aWin, cx)) {
1630 0 : return NS_OK;
1631 : }
1632 :
1633 : // Create the XPConnect prototype for our classinfo, PostCreateProto will
1634 : // set up the prototype chain. This will go ahead and define things on the
1635 : // actual window's global.
1636 0 : JS::Rooted<JSObject*> dot_prototype(cx);
1637 0 : rv = GetXPCProto(nsDOMClassInfo::sXPConnect, cx, aWin, name_struct,
1638 : &dot_prototype);
1639 0 : NS_ENSURE_SUCCESS(rv, rv);
1640 0 : MOZ_ASSERT(dot_prototype);
1641 :
1642 0 : bool isXray = xpc::WrapperFactory::IsXrayWrapper(obj);
1643 0 : MOZ_ASSERT_IF(obj != aWin->GetGlobalJSObject(), isXray);
1644 0 : if (!isXray) {
1645 : // GetXPCProto already defined the property for us
1646 0 : FillPropertyDescriptor(desc, obj, JS::UndefinedValue(), false);
1647 0 : return NS_OK;
1648 : }
1649 :
1650 : // This is the Xray case. Look up the constructor object for this
1651 : // prototype.
1652 0 : return ResolvePrototype(nsDOMClassInfo::sXPConnect, aWin, cx, obj,
1653 : class_name,
1654 0 : &sClassInfoData[name_struct->mDOMClassInfoID],
1655 : name_struct, nameSpaceManager, dot_prototype,
1656 0 : desc);
1657 : }
1658 :
1659 0 : if (name_struct->mType == nsGlobalNameStruct::eTypeClassProto) {
1660 : // We don't have a XPConnect prototype object, let ResolvePrototype create
1661 : // one.
1662 0 : return ResolvePrototype(nsDOMClassInfo::sXPConnect, aWin, cx, obj,
1663 : class_name, nullptr,
1664 0 : name_struct, nameSpaceManager, nullptr, desc);
1665 : }
1666 :
1667 0 : if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructor) {
1668 0 : RefPtr<nsDOMConstructor> constructor;
1669 0 : rv = nsDOMConstructor::Create(class_name, name_struct, aWin->AsInner(),
1670 0 : getter_AddRefs(constructor));
1671 0 : NS_ENSURE_SUCCESS(rv, rv);
1672 :
1673 0 : JS::Rooted<JS::Value> val(cx);
1674 0 : js::AssertSameCompartment(cx, obj);
1675 0 : rv = nsContentUtils::WrapNative(cx, constructor,
1676 : &NS_GET_IID(nsIDOMDOMConstructor), &val,
1677 0 : true);
1678 0 : NS_ENSURE_SUCCESS(rv, rv);
1679 :
1680 0 : NS_ASSERTION(val.isObject(), "Why didn't we get a JSObject?");
1681 :
1682 0 : FillPropertyDescriptor(desc, obj, 0, val);
1683 :
1684 0 : return NS_OK;
1685 : }
1686 :
1687 0 : if (name_struct->mType == nsGlobalNameStruct::eTypeProperty) {
1688 0 : if (!OldBindingConstructorEnabled(name_struct, aWin, cx))
1689 0 : return NS_OK;
1690 :
1691 : // Before defining a global property, check for a named subframe of the
1692 : // same name. If it exists, we don't want to shadow it.
1693 0 : if (nsCOMPtr<nsPIDOMWindowOuter> childWin = aWin->GetChildWindow(name)) {
1694 0 : return NS_OK;
1695 : }
1696 :
1697 0 : nsCOMPtr<nsISupports> native(do_CreateInstance(name_struct->mCID, &rv));
1698 0 : NS_ENSURE_SUCCESS(rv, rv);
1699 :
1700 0 : JS::Rooted<JS::Value> prop_val(cx, JS::UndefinedValue()); // Property value.
1701 :
1702 0 : nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi(do_QueryInterface(native));
1703 0 : if (gpi) {
1704 0 : rv = gpi->Init(aWin->AsInner(), &prop_val);
1705 0 : NS_ENSURE_SUCCESS(rv, rv);
1706 : }
1707 :
1708 0 : if (prop_val.isPrimitive() && !prop_val.isNull()) {
1709 0 : rv = nsContentUtils::WrapNative(cx, native, &prop_val, true);
1710 : }
1711 :
1712 0 : NS_ENSURE_SUCCESS(rv, rv);
1713 :
1714 0 : if (!JS_WrapValue(cx, &prop_val)) {
1715 0 : return NS_ERROR_UNEXPECTED;
1716 : }
1717 :
1718 0 : FillPropertyDescriptor(desc, obj, prop_val, false);
1719 :
1720 0 : return NS_OK;
1721 : }
1722 :
1723 0 : return rv;
1724 : }
1725 :
1726 : struct InterfaceShimEntry {
1727 : const char *geckoName;
1728 : const char *domName;
1729 : };
1730 :
1731 : // We add shims from Components.interfaces.nsIDOMFoo to window.Foo for each
1732 : // interface that has interface constants that sites might be getting off
1733 : // of Ci.
1734 : const InterfaceShimEntry kInterfaceShimMap[] =
1735 : { { "nsIXMLHttpRequest", "XMLHttpRequest" },
1736 : { "nsIDOMDOMException", "DOMException" },
1737 : { "nsIDOMNode", "Node" },
1738 : { "nsIDOMCSSPrimitiveValue", "CSSPrimitiveValue" },
1739 : { "nsIDOMCSSRule", "CSSRule" },
1740 : { "nsIDOMCSSValue", "CSSValue" },
1741 : { "nsIDOMEvent", "Event" },
1742 : { "nsIDOMNSEvent", "Event" },
1743 : { "nsIDOMKeyEvent", "KeyEvent" },
1744 : { "nsIDOMMouseEvent", "MouseEvent" },
1745 : { "nsIDOMMouseScrollEvent", "MouseScrollEvent" },
1746 : { "nsIDOMMutationEvent", "MutationEvent" },
1747 : { "nsIDOMSimpleGestureEvent", "SimpleGestureEvent" },
1748 : { "nsIDOMUIEvent", "UIEvent" },
1749 : { "nsIDOMHTMLMediaElement", "HTMLMediaElement" },
1750 : { "nsIDOMOfflineResourceList", "OfflineResourceList" },
1751 : { "nsIDOMRange", "Range" },
1752 : { "nsIDOMSVGLength", "SVGLength" },
1753 : { "nsIDOMNodeFilter", "NodeFilter" },
1754 : { "nsIDOMXPathResult", "XPathResult" } };
1755 :
1756 : static nsresult
1757 0 : LookupComponentsShim(JSContext *cx, JS::Handle<JSObject*> global,
1758 : nsPIDOMWindowInner *win,
1759 : JS::MutableHandle<JS::PropertyDescriptor> desc)
1760 : {
1761 : // Keep track of how often this happens.
1762 0 : Telemetry::Accumulate(Telemetry::COMPONENTS_SHIM_ACCESSED_BY_CONTENT, true);
1763 :
1764 : // Warn once.
1765 0 : nsCOMPtr<nsIDocument> doc = win->GetExtantDoc();
1766 0 : if (doc) {
1767 0 : doc->WarnOnceAbout(nsIDocument::eComponents, /* asError = */ true);
1768 : }
1769 :
1770 : // Create a fake Components object.
1771 0 : AssertSameCompartment(cx, global);
1772 0 : JS::Rooted<JSObject*> components(cx, JS_NewPlainObject(cx));
1773 0 : NS_ENSURE_TRUE(components, NS_ERROR_OUT_OF_MEMORY);
1774 :
1775 : // Create a fake interfaces object.
1776 0 : JS::Rooted<JSObject*> interfaces(cx, JS_NewPlainObject(cx));
1777 0 : NS_ENSURE_TRUE(interfaces, NS_ERROR_OUT_OF_MEMORY);
1778 : bool ok =
1779 0 : JS_DefineProperty(cx, components, "interfaces", interfaces,
1780 : JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY,
1781 0 : JS_STUBGETTER, JS_STUBSETTER);
1782 0 : NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
1783 :
1784 : // Define a bunch of shims from the Ci.nsIDOMFoo to window.Foo for DOM
1785 : // interfaces with constants.
1786 0 : for (uint32_t i = 0; i < ArrayLength(kInterfaceShimMap); ++i) {
1787 :
1788 : // Grab the names from the table.
1789 0 : const char *geckoName = kInterfaceShimMap[i].geckoName;
1790 0 : const char *domName = kInterfaceShimMap[i].domName;
1791 :
1792 : // Look up the appopriate interface object on the global.
1793 0 : JS::Rooted<JS::Value> v(cx, JS::UndefinedValue());
1794 0 : ok = JS_GetProperty(cx, global, domName, &v);
1795 0 : NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
1796 0 : if (!v.isObject()) {
1797 0 : NS_WARNING("Unable to find interface object on global");
1798 0 : continue;
1799 : }
1800 :
1801 : // Define the shim on the interfaces object.
1802 0 : ok = JS_DefineProperty(cx, interfaces, geckoName, v,
1803 : JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY,
1804 0 : JS_STUBGETTER, JS_STUBSETTER);
1805 0 : NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
1806 : }
1807 :
1808 0 : FillPropertyDescriptor(desc, global, JS::ObjectValue(*components), false);
1809 :
1810 0 : return NS_OK;
1811 : }
1812 :
1813 : // EventTarget helper
1814 :
1815 : NS_IMETHODIMP
1816 0 : nsEventTargetSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
1817 : JSObject *aGlobalObj, JSObject **parentObj)
1818 : {
1819 0 : JS::Rooted<JSObject*> globalObj(cx, aGlobalObj);
1820 0 : DOMEventTargetHelper* target = DOMEventTargetHelper::FromSupports(nativeObj);
1821 :
1822 0 : nsCOMPtr<nsIScriptGlobalObject> native_parent;
1823 0 : target->GetParentObject(getter_AddRefs(native_parent));
1824 :
1825 0 : *parentObj = native_parent ? native_parent->GetGlobalJSObject() : globalObj;
1826 :
1827 0 : return *parentObj ? NS_OK : NS_ERROR_FAILURE;
1828 : }
1829 :
1830 : void
1831 0 : nsEventTargetSH::PreserveWrapper(nsISupports *aNative)
1832 : {
1833 0 : DOMEventTargetHelper* target = DOMEventTargetHelper::FromSupports(aNative);
1834 0 : target->PreserveWrapper(aNative);
1835 0 : }
1836 :
1837 : // nsIDOMEventListener::HandleEvent() 'this' converter helper
1838 :
1839 6 : NS_INTERFACE_MAP_BEGIN(nsEventListenerThisTranslator)
1840 6 : NS_INTERFACE_MAP_ENTRY(nsIXPCFunctionThisTranslator)
1841 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
1842 0 : NS_INTERFACE_MAP_END
1843 :
1844 :
1845 12 : NS_IMPL_ADDREF(nsEventListenerThisTranslator)
1846 9 : NS_IMPL_RELEASE(nsEventListenerThisTranslator)
1847 :
1848 :
1849 : NS_IMETHODIMP
1850 20 : nsEventListenerThisTranslator::TranslateThis(nsISupports *aInitialThis,
1851 : nsISupports **_retval)
1852 : {
1853 40 : nsCOMPtr<nsIDOMEvent> event(do_QueryInterface(aInitialThis));
1854 20 : NS_ENSURE_TRUE(event, NS_ERROR_UNEXPECTED);
1855 :
1856 40 : nsCOMPtr<EventTarget> target = event->InternalDOMEvent()->GetCurrentTarget();
1857 20 : target.forget(_retval);
1858 20 : return NS_OK;
1859 : }
1860 :
1861 : NS_IMETHODIMP
1862 2 : nsDOMConstructorSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
1863 : JSObject *aGlobalObj, JSObject **parentObj)
1864 : {
1865 4 : JS::Rooted<JSObject*> globalObj(cx, aGlobalObj);
1866 2 : nsDOMConstructor *wrapped = static_cast<nsDOMConstructor *>(nativeObj);
1867 :
1868 : #ifdef DEBUG
1869 : {
1870 : nsCOMPtr<nsIDOMDOMConstructor> is_constructor =
1871 4 : do_QueryInterface(nativeObj);
1872 2 : NS_ASSERTION(is_constructor, "How did we not get a constructor?");
1873 : }
1874 : #endif
1875 :
1876 4 : return wrapped->PreCreate(cx, globalObj, parentObj);
1877 : }
1878 :
1879 : NS_IMETHODIMP
1880 2 : nsDOMConstructorSH::Resolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
1881 : JSObject *aObj, jsid aId, bool *resolvedp,
1882 : bool *_retval)
1883 : {
1884 4 : JS::Rooted<JSObject*> obj(cx, aObj);
1885 4 : JS::Rooted<jsid> id(cx, aId);
1886 : // For regular DOM constructors, we have our interface constants defined on
1887 : // us by nsWindowSH::GlobalResolve. However, XrayWrappers can't see these
1888 : // interface constants (as they look like expando properties) so we have to
1889 : // specially resolve those constants here, but only for Xray wrappers.
1890 2 : if (!ObjectIsNativeWrapper(cx, obj)) {
1891 2 : return NS_OK;
1892 : }
1893 :
1894 0 : JS::Rooted<JSObject*> nativePropsObj(cx, xpc::XrayUtils::GetNativePropertiesObject(cx, obj));
1895 : nsDOMConstructor *wrapped =
1896 0 : static_cast<nsDOMConstructor *>(wrapper->Native());
1897 0 : nsresult rv = wrapped->ResolveInterfaceConstants(cx, nativePropsObj);
1898 0 : NS_ENSURE_SUCCESS(rv, rv);
1899 :
1900 : // Now re-lookup the ID to see if we should report back that we resolved the
1901 : // looked-for constant. Note that we don't have to worry about infinitely
1902 : // recurring back here because the Xray wrapper's holder object doesn't call
1903 : // Resolve hooks.
1904 : bool found;
1905 0 : if (!JS_HasPropertyById(cx, nativePropsObj, id, &found)) {
1906 0 : *_retval = false;
1907 0 : return NS_OK;
1908 : }
1909 :
1910 0 : if (found) {
1911 0 : *resolvedp = true;
1912 : }
1913 0 : return NS_OK;
1914 : }
1915 :
1916 : NS_IMETHODIMP
1917 0 : nsDOMConstructorSH::Call(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
1918 : JSObject *aObj, const JS::CallArgs &args, bool *_retval)
1919 : {
1920 0 : JS::Rooted<JSObject*> obj(cx, aObj);
1921 0 : MOZ_ASSERT(obj);
1922 :
1923 : nsDOMConstructor *wrapped =
1924 0 : static_cast<nsDOMConstructor *>(wrapper->Native());
1925 :
1926 : #ifdef DEBUG
1927 : {
1928 : nsCOMPtr<nsIDOMDOMConstructor> is_constructor =
1929 0 : do_QueryWrappedNative(wrapper);
1930 0 : NS_ASSERTION(is_constructor, "How did we not get a constructor?");
1931 : }
1932 : #endif
1933 :
1934 0 : return wrapped->Construct(wrapper, cx, obj, args, _retval);
1935 : }
1936 :
1937 : NS_IMETHODIMP
1938 0 : nsDOMConstructorSH::Construct(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
1939 : JSObject *aObj, const JS::CallArgs &args, bool *_retval)
1940 : {
1941 0 : JS::Rooted<JSObject*> obj(cx, aObj);
1942 0 : MOZ_ASSERT(obj);
1943 :
1944 : nsDOMConstructor *wrapped =
1945 0 : static_cast<nsDOMConstructor *>(wrapper->Native());
1946 :
1947 : #ifdef DEBUG
1948 : {
1949 : nsCOMPtr<nsIDOMDOMConstructor> is_constructor =
1950 0 : do_QueryWrappedNative(wrapper);
1951 0 : NS_ASSERTION(is_constructor, "How did we not get a constructor?");
1952 : }
1953 : #endif
1954 :
1955 0 : return wrapped->Construct(wrapper, cx, obj, args, _retval);
1956 : }
1957 :
1958 : NS_IMETHODIMP
1959 0 : nsDOMConstructorSH::HasInstance(nsIXPConnectWrappedNative *wrapper,
1960 : JSContext *cx, JSObject *aObj, JS::Handle<JS::Value> val,
1961 : bool *bp, bool *_retval)
1962 : {
1963 0 : JS::Rooted<JSObject*> obj(cx, aObj);
1964 : nsDOMConstructor *wrapped =
1965 0 : static_cast<nsDOMConstructor *>(wrapper->Native());
1966 :
1967 : #ifdef DEBUG
1968 : {
1969 : nsCOMPtr<nsIDOMDOMConstructor> is_constructor =
1970 0 : do_QueryWrappedNative(wrapper);
1971 0 : NS_ASSERTION(is_constructor, "How did we not get a constructor?");
1972 : }
1973 : #endif
1974 :
1975 0 : return wrapped->HasInstance(wrapper, cx, obj, val, bp, _retval);
1976 : }
1977 :
1978 : // nsContentFrameMessageManagerSH
1979 :
1980 : template<typename Super>
1981 : NS_IMETHODIMP
1982 587 : nsMessageManagerSH<Super>::Resolve(nsIXPConnectWrappedNative* wrapper,
1983 : JSContext* cx, JSObject* obj_,
1984 : jsid id_, bool* resolvedp,
1985 : bool* _retval)
1986 : {
1987 1174 : JS::Rooted<JSObject*> obj(cx, obj_);
1988 1174 : JS::Rooted<jsid> id(cx, id_);
1989 :
1990 587 : *_retval = SystemGlobalResolve(cx, obj, id, resolvedp);
1991 587 : NS_ENSURE_TRUE(*_retval, NS_ERROR_FAILURE);
1992 :
1993 587 : if (*resolvedp) {
1994 0 : return NS_OK;
1995 : }
1996 :
1997 587 : return Super::Resolve(wrapper, cx, obj, id, resolvedp, _retval);
1998 : }
1999 :
2000 : template<typename Super>
2001 : NS_IMETHODIMP
2002 0 : nsMessageManagerSH<Super>::Enumerate(nsIXPConnectWrappedNative* wrapper,
2003 : JSContext* cx, JSObject* obj_,
2004 : bool* _retval)
2005 : {
2006 0 : JS::Rooted<JSObject*> obj(cx, obj_);
2007 :
2008 0 : *_retval = SystemGlobalEnumerate(cx, obj);
2009 0 : NS_ENSURE_TRUE(*_retval, NS_ERROR_FAILURE);
2010 :
2011 : // Don't call up to our superclass, since neither nsDOMGenericSH nor
2012 : // nsEventTargetSH have WANT_ENUMERATE.
2013 0 : return NS_OK;
2014 : }
|