Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim: set ts=8 sts=4 et sw=4 tw=99: */
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 /* An xpcom implementation of the JavaScript nsIID and nsCID objects. */
9 #include "xpcprivate.h"
10 #include "mozilla/dom/BindingUtils.h"
11 #include "mozilla/Attributes.h"
12 #include "JavaScriptParent.h"
13 #include "mozilla/StaticPtr.h"
15 using namespace mozilla::dom;
16 using namespace JS;
18 /***************************************************************************/
19 // nsJSID
21 NS_IMPL_CLASSINFO(nsJSID, nullptr, 0, NS_JS_ID_CID)
22 NS_IMPL_ISUPPORTS_CI(nsJSID, nsIJSID)
24 char nsJSID::gNoString[] = "";
26 nsJSID::nsJSID()
27 : mID(GetInvalidIID()), mNumber(gNoString), mName(gNoString)
28 {
29 }
31 nsJSID::~nsJSID()
32 {
33 if (mNumber && mNumber != gNoString)
34 NS_Free(mNumber);
35 if (mName && mName != gNoString)
36 NS_Free(mName);
37 }
39 void nsJSID::Reset()
40 {
41 mID = GetInvalidIID();
43 if (mNumber && mNumber != gNoString)
44 NS_Free(mNumber);
45 if (mName && mName != gNoString)
46 NS_Free(mName);
48 mNumber = mName = nullptr;
49 }
51 bool
52 nsJSID::SetName(const char* name)
53 {
54 MOZ_ASSERT(!mName || mName == gNoString ,"name already set");
55 MOZ_ASSERT(name,"null name");
56 mName = NS_strdup(name);
57 return mName ? true : false;
58 }
60 NS_IMETHODIMP
61 nsJSID::GetName(char * *aName)
62 {
63 if (!aName)
64 return NS_ERROR_NULL_POINTER;
66 if (!NameIsSet())
67 SetNameToNoString();
68 MOZ_ASSERT(mName, "name not set");
69 *aName = NS_strdup(mName);
70 return *aName ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
71 }
73 NS_IMETHODIMP
74 nsJSID::GetNumber(char * *aNumber)
75 {
76 if (!aNumber)
77 return NS_ERROR_NULL_POINTER;
79 if (!mNumber) {
80 if (!(mNumber = mID.ToString()))
81 mNumber = gNoString;
82 }
84 *aNumber = NS_strdup(mNumber);
85 return *aNumber ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
86 }
88 NS_IMETHODIMP_(const nsID*)
89 nsJSID::GetID()
90 {
91 return &mID;
92 }
94 NS_IMETHODIMP
95 nsJSID::GetValid(bool *aValid)
96 {
97 if (!aValid)
98 return NS_ERROR_NULL_POINTER;
100 *aValid = IsValid();
101 return NS_OK;
102 }
104 NS_IMETHODIMP
105 nsJSID::Equals(nsIJSID *other, bool *_retval)
106 {
107 if (!_retval)
108 return NS_ERROR_NULL_POINTER;
110 if (!other || mID.Equals(GetInvalidIID())) {
111 *_retval = false;
112 return NS_OK;
113 }
115 *_retval = other->GetID()->Equals(mID);
116 return NS_OK;
117 }
119 NS_IMETHODIMP
120 nsJSID::Initialize(const char *idString)
121 {
122 if (!idString)
123 return NS_ERROR_NULL_POINTER;
125 if (*idString != '\0' && mID.Equals(GetInvalidIID())) {
126 Reset();
128 if (idString[0] == '{') {
129 if (mID.Parse(idString)) {
130 return NS_OK;
131 }
133 // error - reset to invalid state
134 mID = GetInvalidIID();
135 }
136 }
137 return NS_ERROR_FAILURE;
138 }
140 bool
141 nsJSID::InitWithName(const nsID& id, const char *nameString)
142 {
143 MOZ_ASSERT(nameString, "no name");
144 Reset();
145 mID = id;
146 return SetName(nameString);
147 }
149 // try to use the name, if no name, then use the number
150 NS_IMETHODIMP
151 nsJSID::ToString(char **_retval)
152 {
153 if (mName && mName != gNoString)
154 return GetName(_retval);
156 return GetNumber(_retval);
157 }
159 const nsID&
160 nsJSID::GetInvalidIID() const
161 {
162 // {BB1F47B0-D137-11d2-9841-006008962422}
163 static const nsID invalid = {0xbb1f47b0, 0xd137, 0x11d2,
164 {0x98, 0x41, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22}};
165 return invalid;
166 }
168 //static
169 already_AddRefed<nsJSID>
170 nsJSID::NewID(const char* str)
171 {
172 if (!str) {
173 NS_ERROR("no string");
174 return nullptr;
175 }
177 nsRefPtr<nsJSID> idObj = new nsJSID();
178 NS_ENSURE_SUCCESS(idObj->Initialize(str), nullptr);
179 return idObj.forget();
180 }
182 //static
183 already_AddRefed<nsJSID>
184 nsJSID::NewID(const nsID& id)
185 {
186 nsRefPtr<nsJSID> idObj = new nsJSID();
187 idObj->mID = id;
188 idObj->mName = nullptr;
189 idObj->mNumber = nullptr;
190 return idObj.forget();
191 }
194 /***************************************************************************/
195 // Class object support so that we can share prototypes of wrapper
197 // This class exists just so we can have a shared scriptable helper for
198 // the nsJSIID class. The instances implement their own helpers. But we
199 // needed to be able to indicate to the shared prototypes this single flag:
200 // nsIXPCScriptable::DONT_ENUM_STATIC_PROPS. And having a class to do it is
201 // the only means we have. Setting this flag on any given instance scriptable
202 // helper is not sufficient to convey the information that we don't want
203 // static properties enumerated on the shared proto.
205 class SharedScriptableHelperForJSIID MOZ_FINAL : public nsIXPCScriptable
206 {
207 public:
208 NS_DECL_ISUPPORTS
209 NS_DECL_NSIXPCSCRIPTABLE
210 SharedScriptableHelperForJSIID() {}
211 };
213 NS_INTERFACE_MAP_BEGIN(SharedScriptableHelperForJSIID)
214 NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable)
215 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCScriptable)
216 NS_INTERFACE_MAP_END
218 NS_IMPL_ADDREF(SharedScriptableHelperForJSIID)
219 NS_IMPL_RELEASE(SharedScriptableHelperForJSIID)
221 // The nsIXPCScriptable map declaration that will generate stubs for us...
222 #define XPC_MAP_CLASSNAME SharedScriptableHelperForJSIID
223 #define XPC_MAP_QUOTED_CLASSNAME "JSIID"
224 #define XPC_MAP_FLAGS nsIXPCScriptable::DONT_ENUM_STATIC_PROPS |\
225 nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE
226 #include "xpc_map_end.h" /* This will #undef the above */
228 static mozilla::StaticRefPtr<nsIXPCScriptable> gSharedScriptableHelperForJSIID;
229 static bool gClassObjectsWereInited = false;
231 static void EnsureClassObjectsInitialized()
232 {
233 if (!gClassObjectsWereInited) {
234 gSharedScriptableHelperForJSIID = new SharedScriptableHelperForJSIID();
236 gClassObjectsWereInited = true;
237 }
238 }
240 NS_METHOD GetSharedScriptableHelperForJSIID(uint32_t language,
241 nsISupports **helper)
242 {
243 EnsureClassObjectsInitialized();
244 if (language == nsIProgrammingLanguage::JAVASCRIPT) {
245 nsCOMPtr<nsIXPCScriptable> temp = gSharedScriptableHelperForJSIID.get();
246 temp.forget(helper);
247 } else
248 *helper = nullptr;
249 return NS_OK;
250 }
252 /******************************************************/
254 #define NULL_CID \
255 { 0x00000000, 0x0000, 0x0000, \
256 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }
258 // We pass nsIClassInfo::DOM_OBJECT so that nsJSIID instances may be created
259 // in unprivileged scopes.
260 NS_DECL_CI_INTERFACE_GETTER(nsJSIID)
261 NS_IMPL_CLASSINFO(nsJSIID, GetSharedScriptableHelperForJSIID,
262 nsIClassInfo::DOM_OBJECT, NULL_CID)
264 NS_DECL_CI_INTERFACE_GETTER(nsJSCID)
265 NS_IMPL_CLASSINFO(nsJSCID, nullptr, 0, NULL_CID)
267 void xpc_DestroyJSxIDClassObjects()
268 {
269 if (gClassObjectsWereInited) {
270 NS_IF_RELEASE(NS_CLASSINFO_NAME(nsJSIID));
271 NS_IF_RELEASE(NS_CLASSINFO_NAME(nsJSCID));
272 gSharedScriptableHelperForJSIID = nullptr;
274 gClassObjectsWereInited = false;
275 }
276 }
278 /***************************************************************************/
280 NS_INTERFACE_MAP_BEGIN(nsJSIID)
281 NS_INTERFACE_MAP_ENTRY(nsIJSID)
282 NS_INTERFACE_MAP_ENTRY(nsIJSIID)
283 NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable)
284 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIJSID)
285 NS_IMPL_QUERY_CLASSINFO(nsJSIID)
286 NS_INTERFACE_MAP_END
288 NS_IMPL_ADDREF(nsJSIID)
289 NS_IMPL_RELEASE(nsJSIID)
290 NS_IMPL_CI_INTERFACE_GETTER(nsJSIID, nsIJSID, nsIJSIID)
292 // The nsIXPCScriptable map declaration that will generate stubs for us...
293 #define XPC_MAP_CLASSNAME nsJSIID
294 #define XPC_MAP_QUOTED_CLASSNAME "nsJSIID"
295 #define XPC_MAP_WANT_NEWRESOLVE
296 #define XPC_MAP_WANT_ENUMERATE
297 #define XPC_MAP_WANT_HASINSTANCE
298 #define XPC_MAP_FLAGS nsIXPCScriptable::DONT_ENUM_STATIC_PROPS |\
299 nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE
300 #include "xpc_map_end.h" /* This will #undef the above */
303 nsJSIID::nsJSIID(nsIInterfaceInfo* aInfo)
304 : mInfo(aInfo)
305 {
306 }
308 nsJSIID::~nsJSIID() {}
310 // If mInfo is present we use it and ignore mDetails, else we use mDetails.
312 NS_IMETHODIMP nsJSIID::GetName(char * *aName)
313 {
314 return mInfo->GetName(aName);
315 }
317 NS_IMETHODIMP nsJSIID::GetNumber(char * *aNumber)
318 {
319 char str[NSID_LENGTH];
320 const nsIID* id;
321 mInfo->GetIIDShared(&id);
322 id->ToProvidedString(str);
323 *aNumber = (char*) nsMemory::Clone(str, NSID_LENGTH);
324 return *aNumber ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
325 }
327 NS_IMETHODIMP_(const nsID*) nsJSIID::GetID()
328 {
329 const nsIID* id;
330 mInfo->GetIIDShared(&id);
331 return id;
332 }
334 NS_IMETHODIMP nsJSIID::GetValid(bool *aValid)
335 {
336 *aValid = true;
337 return NS_OK;
338 }
340 NS_IMETHODIMP nsJSIID::Equals(nsIJSID *other, bool *_retval)
341 {
342 if (!_retval)
343 return NS_ERROR_NULL_POINTER;
345 if (!other) {
346 *_retval = false;
347 return NS_OK;
348 }
350 mInfo->IsIID(other->GetID(), _retval);
351 return NS_OK;
352 }
354 NS_IMETHODIMP nsJSIID::Initialize(const char *idString)
355 {
356 return NS_ERROR_FAILURE;
357 }
359 NS_IMETHODIMP nsJSIID::ToString(char **_retval)
360 {
361 return mInfo->GetName(_retval);
362 }
364 // static
365 already_AddRefed<nsJSIID>
366 nsJSIID::NewID(nsIInterfaceInfo* aInfo)
367 {
368 if (!aInfo) {
369 NS_ERROR("no info");
370 return nullptr;
371 }
373 bool canScript;
374 if (NS_FAILED(aInfo->IsScriptable(&canScript)) || !canScript)
375 return nullptr;
377 nsRefPtr<nsJSIID> idObj = new nsJSIID(aInfo);
378 return idObj.forget();
379 }
382 /* bool resolve (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsval id); */
383 NS_IMETHODIMP
384 nsJSIID::NewResolve(nsIXPConnectWrappedNative *wrapper,
385 JSContext * cx, JSObject * objArg,
386 jsid idArg, JSObject * *objp,
387 bool *_retval)
388 {
389 RootedObject obj(cx, objArg);
390 RootedId id(cx, idArg);
391 XPCCallContext ccx(JS_CALLER, cx);
393 AutoMarkingNativeInterfacePtr iface(ccx);
395 const nsIID* iid;
396 mInfo->GetIIDShared(&iid);
398 iface = XPCNativeInterface::GetNewOrUsed(iid);
400 if (!iface)
401 return NS_OK;
403 XPCNativeMember* member = iface->FindMember(id);
404 if (member && member->IsConstant()) {
405 RootedValue val(cx);
406 if (!member->GetConstantValue(ccx, iface, val.address()))
407 return NS_ERROR_OUT_OF_MEMORY;
409 *objp = obj;
410 *_retval = JS_DefinePropertyById(cx, obj, id, val, nullptr, nullptr,
411 JSPROP_ENUMERATE | JSPROP_READONLY |
412 JSPROP_PERMANENT);
413 }
415 return NS_OK;
416 }
418 /* bool enumerate (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj); */
419 NS_IMETHODIMP
420 nsJSIID::Enumerate(nsIXPConnectWrappedNative *wrapper,
421 JSContext * cx, JSObject * objArg, bool *_retval)
422 {
423 // In this case, let's just eagerly resolve...
425 RootedObject obj(cx, objArg);
426 XPCCallContext ccx(JS_CALLER, cx);
428 AutoMarkingNativeInterfacePtr iface(ccx);
430 const nsIID* iid;
431 mInfo->GetIIDShared(&iid);
433 iface = XPCNativeInterface::GetNewOrUsed(iid);
435 if (!iface)
436 return NS_OK;
438 uint16_t count = iface->GetMemberCount();
439 for (uint16_t i = 0; i < count; i++) {
440 XPCNativeMember* member = iface->GetMemberAt(i);
441 if (member && member->IsConstant() &&
442 !xpc_ForcePropertyResolve(cx, obj, member->GetName())) {
443 return NS_ERROR_UNEXPECTED;
444 }
445 }
446 return NS_OK;
447 }
449 /*
450 * HasInstance hooks need to find an appropriate reflector in order to function
451 * properly. There are two complexities that we need to handle:
452 *
453 * 1 - Cross-compartment wrappers. Chrome uses over 100 compartments, all with
454 * system principal. The success of an instanceof check should not depend
455 * on which compartment an object comes from. At the same time, we want to
456 * make sure we don't unwrap important security wrappers.
457 * CheckedUnwrap does the right thing here.
458 *
459 * 2 - Prototype chains. Suppose someone creates a vanilla JS object |a| and
460 * sets its __proto__ to some WN |b|. If |b instanceof nsIFoo| returns true,
461 * one would expect |a instanceof nsIFoo| to return true as well, since
462 * instanceof is transitive up the prototype chain in ECMAScript. Moreover,
463 * there's chrome code that relies on this.
464 *
465 * This static method handles both complexities, returning either an XPCWN, a
466 * DOM object, or null. The object may well be cross-compartment from |cx|.
467 */
468 static JSObject *
469 FindObjectForHasInstance(JSContext *cx, HandleObject objArg)
470 {
471 RootedObject obj(cx, objArg), proto(cx);
473 while (obj && !IS_WN_REFLECTOR(obj) &&
474 !IsDOMObject(obj) && !mozilla::jsipc::JavaScriptParent::IsCPOW(obj))
475 {
476 if (js::IsWrapper(obj)) {
477 obj = js::CheckedUnwrap(obj, /* stopAtOuter = */ false);
478 continue;
479 }
480 if (!js::GetObjectProto(cx, obj, &proto))
481 return nullptr;
482 obj = proto;
483 }
484 return obj;
485 }
487 nsresult
488 xpc::HasInstance(JSContext *cx, HandleObject objArg, const nsID *iid, bool *bp)
489 {
490 *bp = false;
492 RootedObject obj(cx, FindObjectForHasInstance(cx, objArg));
493 if (!obj)
494 return NS_OK;
496 if (IsDOMObject(obj)) {
497 // Not all DOM objects implement nsISupports. But if they don't,
498 // there's nothing to do in this HasInstance hook.
499 nsISupports *identity = UnwrapDOMObjectToISupports(obj);
500 if (!identity)
501 return NS_OK;;
502 nsCOMPtr<nsISupports> supp;
503 identity->QueryInterface(*iid, getter_AddRefs(supp));
504 *bp = supp;
505 return NS_OK;
506 }
508 if (mozilla::jsipc::JavaScriptParent::IsCPOW(obj))
509 return mozilla::jsipc::JavaScriptParent::InstanceOf(obj, iid, bp);
511 MOZ_ASSERT(IS_WN_REFLECTOR(obj));
512 XPCWrappedNative* other_wrapper = XPCWrappedNative::Get(obj);
513 if (!other_wrapper)
514 return NS_OK;
516 // We'll trust the interface set of the wrapper if this is known
517 // to be an interface that the objects *expects* to be able to
518 // handle.
519 if (other_wrapper->HasInterfaceNoQI(*iid)) {
520 *bp = true;
521 return NS_OK;
522 }
524 // Otherwise, we'll end up Querying the native object to be sure.
525 XPCCallContext ccx(JS_CALLER, cx);
527 AutoMarkingNativeInterfacePtr iface(ccx);
528 iface = XPCNativeInterface::GetNewOrUsed(iid);
530 nsresult findResult = NS_OK;
531 if (iface && other_wrapper->FindTearOff(iface, false, &findResult))
532 *bp = true;
533 if (NS_FAILED(findResult) && findResult != NS_ERROR_NO_INTERFACE)
534 return findResult;
536 return NS_OK;
537 }
539 /* bool hasInstance (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsval val, out bool bp); */
540 NS_IMETHODIMP
541 nsJSIID::HasInstance(nsIXPConnectWrappedNative *wrapper,
542 JSContext *cx, JSObject * /* unused */,
543 HandleValue val, bool *bp, bool *_retval)
544 {
545 *bp = false;
547 if (val.isPrimitive())
548 return NS_OK;
550 // we have a JSObject
551 RootedObject obj(cx, &val.toObject());
553 const nsIID* iid;
554 mInfo->GetIIDShared(&iid);
555 return xpc::HasInstance(cx, obj, iid, bp);
556 }
558 /***************************************************************************/
560 NS_INTERFACE_MAP_BEGIN(nsJSCID)
561 NS_INTERFACE_MAP_ENTRY(nsIJSID)
562 NS_INTERFACE_MAP_ENTRY(nsIJSCID)
563 NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable)
564 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIJSID)
565 NS_IMPL_QUERY_CLASSINFO(nsJSCID)
566 NS_INTERFACE_MAP_END
568 NS_IMPL_ADDREF(nsJSCID)
569 NS_IMPL_RELEASE(nsJSCID)
570 NS_IMPL_CI_INTERFACE_GETTER(nsJSCID, nsIJSID, nsIJSCID)
572 // The nsIXPCScriptable map declaration that will generate stubs for us...
573 #define XPC_MAP_CLASSNAME nsJSCID
574 #define XPC_MAP_QUOTED_CLASSNAME "nsJSCID"
575 #define XPC_MAP_WANT_CONSTRUCT
576 #define XPC_MAP_WANT_HASINSTANCE
577 #define XPC_MAP_FLAGS 0
578 #include "xpc_map_end.h" /* This will #undef the above */
580 nsJSCID::nsJSCID() {}
581 nsJSCID::~nsJSCID() {}
583 NS_IMETHODIMP nsJSCID::GetName(char * *aName)
584 {ResolveName(); return mDetails.GetName(aName);}
586 NS_IMETHODIMP nsJSCID::GetNumber(char * *aNumber)
587 {return mDetails.GetNumber(aNumber);}
589 NS_IMETHODIMP_(const nsID*) nsJSCID::GetID()
590 {return &mDetails.ID();}
592 NS_IMETHODIMP nsJSCID::GetValid(bool *aValid)
593 {return mDetails.GetValid(aValid);}
595 NS_IMETHODIMP nsJSCID::Equals(nsIJSID *other, bool *_retval)
596 {return mDetails.Equals(other, _retval);}
598 NS_IMETHODIMP nsJSCID::Initialize(const char *idString)
599 {return mDetails.Initialize(idString);}
601 NS_IMETHODIMP nsJSCID::ToString(char **_retval)
602 {ResolveName(); return mDetails.ToString(_retval);}
604 void
605 nsJSCID::ResolveName()
606 {
607 if (!mDetails.NameIsSet())
608 mDetails.SetNameToNoString();
609 }
611 //static
612 already_AddRefed<nsJSCID>
613 nsJSCID::NewID(const char* str)
614 {
615 if (!str) {
616 NS_ERROR("no string");
617 return nullptr;
618 }
620 nsRefPtr<nsJSCID> idObj = new nsJSCID();
621 if (str[0] == '{') {
622 NS_ENSURE_SUCCESS(idObj->Initialize(str), nullptr);
623 } else {
624 nsCOMPtr<nsIComponentRegistrar> registrar;
625 NS_GetComponentRegistrar(getter_AddRefs(registrar));
626 NS_ENSURE_TRUE(registrar, nullptr);
628 nsCID *cid;
629 if (NS_FAILED(registrar->ContractIDToCID(str, &cid)))
630 return nullptr;
631 bool success = idObj->mDetails.InitWithName(*cid, str);
632 nsMemory::Free(cid);
633 if (!success)
634 return nullptr;
635 }
636 return idObj.forget();
637 }
639 static const nsID*
640 GetIIDArg(uint32_t argc, const JS::Value& val, JSContext* cx)
641 {
642 const nsID* iid;
644 // If an IID was passed in then use it
645 if (argc) {
646 JSObject* iidobj;
647 if (JSVAL_IS_PRIMITIVE(val) ||
648 !(iidobj = JSVAL_TO_OBJECT(val)) ||
649 !(iid = xpc_JSObjectToID(cx, iidobj))) {
650 return nullptr;
651 }
652 } else
653 iid = &NS_GET_IID(nsISupports);
655 return iid;
656 }
658 static void
659 GetWrapperObject(MutableHandleObject obj)
660 {
661 obj.set(nullptr);
662 nsXPConnect* xpc = nsXPConnect::XPConnect();
663 nsAXPCNativeCallContext *ccxp = nullptr;
664 xpc->GetCurrentNativeCallContext(&ccxp);
665 if (!ccxp)
666 return;
668 nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
669 ccxp->GetCalleeWrapper(getter_AddRefs(wrapper));
670 obj.set(wrapper->GetJSObject());
671 }
673 /* nsISupports createInstance (); */
674 NS_IMETHODIMP
675 nsJSCID::CreateInstance(HandleValue iidval, JSContext *cx,
676 uint8_t optionalArgc, MutableHandleValue retval)
677 {
678 if (!mDetails.IsValid())
679 return NS_ERROR_XPC_BAD_CID;
681 RootedObject obj(cx);
682 GetWrapperObject(&obj);
683 if (!obj) {
684 return NS_ERROR_UNEXPECTED;
685 }
687 nsIXPCSecurityManager* sm = nsXPConnect::XPConnect()->GetDefaultSecurityManager();
688 if (sm && NS_FAILED(sm->CanCreateInstance(cx, mDetails.ID()))) {
689 NS_ERROR("how are we not being called from chrome here?");
690 return NS_OK;
691 }
693 // If an IID was passed in then use it
694 const nsID* iid = GetIIDArg(optionalArgc, iidval, cx);
695 if (!iid)
696 return NS_ERROR_XPC_BAD_IID;
698 nsCOMPtr<nsIComponentManager> compMgr;
699 nsresult rv = NS_GetComponentManager(getter_AddRefs(compMgr));
700 if (NS_FAILED(rv))
701 return NS_ERROR_UNEXPECTED;
703 nsCOMPtr<nsISupports> inst;
704 rv = compMgr->CreateInstance(mDetails.ID(), nullptr, *iid, getter_AddRefs(inst));
705 MOZ_ASSERT(NS_FAILED(rv) || inst, "component manager returned success, but instance is null!");
707 if (NS_FAILED(rv) || !inst)
708 return NS_ERROR_XPC_CI_RETURNED_FAILURE;
710 rv = nsXPConnect::XPConnect()->WrapNativeToJSVal(cx, obj, inst, nullptr, iid, true, retval);
711 if (NS_FAILED(rv) || retval.isPrimitive())
712 return NS_ERROR_XPC_CANT_CREATE_WN;
713 return NS_OK;
714 }
716 /* nsISupports getService (); */
717 NS_IMETHODIMP
718 nsJSCID::GetService(HandleValue iidval, JSContext *cx, uint8_t optionalArgc,
719 MutableHandleValue retval)
720 {
721 if (!mDetails.IsValid())
722 return NS_ERROR_XPC_BAD_CID;
724 RootedObject obj(cx);
725 GetWrapperObject(&obj);
726 if (!obj) {
727 return NS_ERROR_UNEXPECTED;
728 }
730 nsIXPCSecurityManager *sm;
731 sm = nsXPConnect::XPConnect()->GetDefaultSecurityManager();
732 if (sm && NS_FAILED(sm->CanCreateInstance(cx, mDetails.ID()))) {
733 MOZ_ASSERT(JS_IsExceptionPending(cx),
734 "security manager vetoed GetService without setting exception");
735 return NS_OK;
736 }
738 // If an IID was passed in then use it
739 const nsID *iid = GetIIDArg(optionalArgc, iidval, cx);
740 if (!iid)
741 return NS_ERROR_XPC_BAD_IID;
743 nsCOMPtr<nsIServiceManager> svcMgr;
744 nsresult rv = NS_GetServiceManager(getter_AddRefs(svcMgr));
745 if (NS_FAILED(rv))
746 return rv;
748 nsCOMPtr<nsISupports> srvc;
749 rv = svcMgr->GetService(mDetails.ID(), *iid, getter_AddRefs(srvc));
750 MOZ_ASSERT(NS_FAILED(rv) || srvc, "service manager returned success, but service is null!");
751 if (NS_FAILED(rv) || !srvc)
752 return NS_ERROR_XPC_GS_RETURNED_FAILURE;
754 nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
755 rv = nsXPConnect::XPConnect()->WrapNative(cx, obj, srvc, *iid, getter_AddRefs(holder));
756 if (NS_FAILED(rv) || !holder || !holder->GetJSObject())
757 return NS_ERROR_XPC_CANT_CREATE_WN;
759 retval.setObject(*holder->GetJSObject());
760 return NS_OK;
761 }
763 /* bool construct (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in uint32_t argc, in JSValPtr argv, in JSValPtr vp); */
764 NS_IMETHODIMP
765 nsJSCID::Construct(nsIXPConnectWrappedNative *wrapper,
766 JSContext *cx, JSObject *objArg,
767 const CallArgs &args, bool *_retval)
768 {
769 RootedObject obj(cx, objArg);
770 XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
771 if (!rt)
772 return NS_ERROR_FAILURE;
774 // 'push' a call context and call on it
775 RootedId name(cx, rt->GetStringID(XPCJSRuntime::IDX_CREATE_INSTANCE));
776 XPCCallContext ccx(JS_CALLER, cx, obj, JS::NullPtr(), name, args.length(), args.array(),
777 args.rval().address());
779 *_retval = XPCWrappedNative::CallMethod(ccx);
780 return NS_OK;
781 }
783 /* bool hasInstance (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsval val, out bool bp); */
784 NS_IMETHODIMP
785 nsJSCID::HasInstance(nsIXPConnectWrappedNative *wrapper,
786 JSContext *cx, JSObject * /* unused */,
787 HandleValue val, bool *bp, bool *_retval)
788 {
789 *bp = false;
790 nsresult rv = NS_OK;
792 if (val.isObject()) {
793 // we have a JSObject
794 RootedObject obj(cx, &val.toObject());
796 MOZ_ASSERT(obj, "when is an object not an object?");
798 // is this really a native xpcom object with a wrapper?
799 nsIClassInfo *ci = nullptr;
800 obj = FindObjectForHasInstance(cx, obj);
801 if (!obj || !IS_WN_REFLECTOR(obj))
802 return rv;
803 if (XPCWrappedNative *other_wrapper = XPCWrappedNative::Get(obj))
804 ci = other_wrapper->GetClassInfo();
806 // We consider CID equality to be the thing that matters here.
807 // This is perhaps debatable.
808 if (ci) {
809 nsID cid;
810 if (NS_SUCCEEDED(ci->GetClassIDNoAlloc(&cid)))
811 *bp = cid.Equals(mDetails.ID());
812 }
813 }
815 return rv;
816 }
818 /***************************************************************************/
819 // additional utilities...
821 JSObject *
822 xpc_NewIDObject(JSContext *cx, HandleObject jsobj, const nsID& aID)
823 {
824 RootedObject obj(cx);
826 nsCOMPtr<nsIJSID> iid = nsJSID::NewID(aID);
827 if (iid) {
828 nsXPConnect *xpc = nsXPConnect::XPConnect();
829 if (xpc) {
830 nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
831 nsresult rv = xpc->WrapNative(cx, jsobj,
832 static_cast<nsISupports*>(iid),
833 NS_GET_IID(nsIJSID),
834 getter_AddRefs(holder));
835 if (NS_SUCCEEDED(rv) && holder) {
836 obj = holder->GetJSObject();
837 }
838 }
839 }
840 return obj;
841 }
843 // note: returned pointer is only valid while |obj| remains alive!
844 const nsID*
845 xpc_JSObjectToID(JSContext *cx, JSObject *obj)
846 {
847 if (!cx || !obj)
848 return nullptr;
850 // NOTE: this call does NOT addref
851 XPCWrappedNative *wrapper = nullptr;
852 obj = js::CheckedUnwrap(obj);
853 if (obj && IS_WN_REFLECTOR(obj))
854 wrapper = XPCWrappedNative::Get(obj);
855 if (wrapper &&
856 (wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSID)) ||
857 wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSIID)) ||
858 wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSCID)))) {
859 return ((nsIJSID*)wrapper->GetIdentityObject())->GetID();
860 }
861 return nullptr;
862 }
864 bool
865 xpc_JSObjectIsID(JSContext *cx, JSObject *obj)
866 {
867 MOZ_ASSERT(cx && obj, "bad param");
868 // NOTE: this call does NOT addref
869 XPCWrappedNative *wrapper = nullptr;
870 obj = js::CheckedUnwrap(obj);
871 if (obj && IS_WN_REFLECTOR(obj))
872 wrapper = XPCWrappedNative::Get(obj);
873 return wrapper &&
874 (wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSID)) ||
875 wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSIID)) ||
876 wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSCID)));
877 }