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 file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/ToJSValue.h"
8 #include "mozilla/dom/DOMException.h"
9 #include "mozilla/dom/Exceptions.h"
10 #include "mozilla/dom/Promise.h"
11 #include "mozilla/dom/WindowProxyHolder.h"
12 #include "nsAString.h"
13 #include "nsContentUtils.h"
14 #include "nsStringBuffer.h"
15 #include "xpcpublic.h"
17 namespace mozilla::dom
{
19 bool ToJSValue(JSContext
* aCx
, const nsAString
& aArgument
,
20 JS::MutableHandle
<JS::Value
> aValue
) {
21 // Make sure we're called in a compartment
22 MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx
));
24 // XXXkhuey I'd love to use xpc::NonVoidStringToJsval here, but it requires
25 // a non-const nsAString for silly reasons.
26 nsStringBuffer
* sharedBuffer
;
27 if (!XPCStringConvert::ReadableToJSVal(aCx
, aArgument
, &sharedBuffer
,
33 NS_ADDREF(sharedBuffer
);
39 bool ToJSValue(JSContext
* aCx
, const nsACString
& aArgument
,
40 JS::MutableHandle
<JS::Value
> aValue
) {
41 return UTF8StringToJsval(aCx
, aArgument
, aValue
);
44 bool ToJSValue(JSContext
* aCx
, nsresult aArgument
,
45 JS::MutableHandle
<JS::Value
> aValue
) {
46 RefPtr
<Exception
> exception
= CreateException(aArgument
);
47 return ToJSValue(aCx
, exception
, aValue
);
50 bool ToJSValue(JSContext
* aCx
, ErrorResult
&& aArgument
,
51 JS::MutableHandle
<JS::Value
> aValue
) {
52 MOZ_ASSERT(aArgument
.Failed());
54 !aArgument
.IsUncatchableException(),
55 "Doesn't make sense to convert uncatchable exception to a JS value!");
56 MOZ_ALWAYS_TRUE(aArgument
.MaybeSetPendingException(aCx
));
57 MOZ_ALWAYS_TRUE(JS_GetPendingException(aCx
, aValue
));
58 JS_ClearPendingException(aCx
);
62 bool ToJSValue(JSContext
* aCx
, Promise
& aArgument
,
63 JS::MutableHandle
<JS::Value
> aValue
) {
64 aValue
.setObject(*aArgument
.PromiseObj());
65 return MaybeWrapObjectValue(aCx
, aValue
);
68 bool ToJSValue(JSContext
* aCx
, const WindowProxyHolder
& aArgument
,
69 JS::MutableHandle
<JS::Value
> aValue
) {
70 BrowsingContext
* bc
= aArgument
.get();
75 JS::Rooted
<JSObject
*> windowProxy(aCx
);
76 if (bc
->IsInProcess()) {
77 windowProxy
= bc
->GetWindowProxy();
79 nsPIDOMWindowOuter
* window
= bc
->GetDOMWindow();
81 // Torn down enough that we should just return null.
85 if (!window
->EnsureInnerWindow()) {
86 return Throw(aCx
, NS_ERROR_UNEXPECTED
);
88 windowProxy
= bc
->GetWindowProxy();
90 return ToJSValue(aCx
, windowProxy
, aValue
);
93 if (!GetRemoteOuterWindowProxy(aCx
, bc
, /* aTransplantTo = */ nullptr,
97 aValue
.setObjectOrNull(windowProxy
);
101 // Static assertion tests for the `binding_detail::ScriptableInterfaceType`
102 // helper template, used by `ToJSValue`.
103 namespace binding_detail
{
104 static_assert(std::is_same_v
<ScriptableInterfaceType
<nsISupports
>, nsISupports
>,
105 "nsISupports works with ScriptableInterfaceType");
107 std::is_same_v
<ScriptableInterfaceType
<nsIGlobalObject
>, nsISupports
>,
108 "non-scriptable interfaces get a fallback");
109 static_assert(std::is_same_v
<ScriptableInterfaceType
<nsIObserver
>, nsIObserver
>,
110 "scriptable interfaces should get the correct type");
111 static_assert(std::is_same_v
<ScriptableInterfaceType
<nsIRunnable
>, nsIRunnable
>,
112 "scriptable interfaces should get the correct type");
113 class SingleScriptableInterface
: public nsIObserver
{};
115 std::is_same_v
<ScriptableInterfaceType
<SingleScriptableInterface
>,
117 "Concrete type with one scriptable interface picks the correct interface");
118 class MultiScriptableInterface
: public nsIObserver
, public nsIRunnable
{};
119 static_assert(std::is_same_v
<ScriptableInterfaceType
<MultiScriptableInterface
>,
121 "Concrete type with multiple scriptable interfaces falls back");
122 } // namespace binding_detail
123 } // namespace mozilla::dom