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 "mozilla/StringBuffer.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
));
23 return xpc::NonVoidStringToJsval(aCx
, aArgument
, aValue
);
26 bool ToJSValue(JSContext
* aCx
, const nsACString
& aArgument
,
27 JS::MutableHandle
<JS::Value
> aValue
) {
28 return UTF8StringToJsval(aCx
, aArgument
, aValue
);
31 bool ToJSValue(JSContext
* aCx
, nsresult aArgument
,
32 JS::MutableHandle
<JS::Value
> aValue
) {
33 RefPtr
<Exception
> exception
= CreateException(aArgument
);
34 return ToJSValue(aCx
, exception
, aValue
);
37 bool ToJSValue(JSContext
* aCx
, ErrorResult
&& aArgument
,
38 JS::MutableHandle
<JS::Value
> aValue
) {
39 MOZ_ASSERT(aArgument
.Failed());
41 !aArgument
.IsUncatchableException(),
42 "Doesn't make sense to convert uncatchable exception to a JS value!");
43 MOZ_ALWAYS_TRUE(aArgument
.MaybeSetPendingException(aCx
));
44 MOZ_ALWAYS_TRUE(JS_GetPendingException(aCx
, aValue
));
45 JS_ClearPendingException(aCx
);
49 bool ToJSValue(JSContext
* aCx
, Promise
& aArgument
,
50 JS::MutableHandle
<JS::Value
> aValue
) {
51 aValue
.setObject(*aArgument
.PromiseObj());
52 return MaybeWrapObjectValue(aCx
, aValue
);
55 bool ToJSValue(JSContext
* aCx
, const WindowProxyHolder
& aArgument
,
56 JS::MutableHandle
<JS::Value
> aValue
) {
57 BrowsingContext
* bc
= aArgument
.get();
62 JS::Rooted
<JSObject
*> windowProxy(aCx
);
63 if (bc
->IsInProcess()) {
64 windowProxy
= bc
->GetWindowProxy();
66 nsPIDOMWindowOuter
* window
= bc
->GetDOMWindow();
68 // Torn down enough that we should just return null.
72 if (!window
->EnsureInnerWindow()) {
73 return Throw(aCx
, NS_ERROR_UNEXPECTED
);
75 windowProxy
= bc
->GetWindowProxy();
77 return ToJSValue(aCx
, windowProxy
, aValue
);
80 if (!GetRemoteOuterWindowProxy(aCx
, bc
, /* aTransplantTo = */ nullptr,
84 aValue
.setObjectOrNull(windowProxy
);
88 // Static assertion tests for the `binding_detail::ScriptableInterfaceType`
89 // helper template, used by `ToJSValue`.
90 namespace binding_detail
{
91 static_assert(std::is_same_v
<ScriptableInterfaceType
<nsISupports
>, nsISupports
>,
92 "nsISupports works with ScriptableInterfaceType");
94 std::is_same_v
<ScriptableInterfaceType
<nsIGlobalObject
>, nsISupports
>,
95 "non-scriptable interfaces get a fallback");
96 static_assert(std::is_same_v
<ScriptableInterfaceType
<nsIObserver
>, nsIObserver
>,
97 "scriptable interfaces should get the correct type");
98 static_assert(std::is_same_v
<ScriptableInterfaceType
<nsIRunnable
>, nsIRunnable
>,
99 "scriptable interfaces should get the correct type");
100 class SingleScriptableInterface
: public nsIObserver
{};
102 std::is_same_v
<ScriptableInterfaceType
<SingleScriptableInterface
>,
104 "Concrete type with one scriptable interface picks the correct interface");
105 class MultiScriptableInterface
: public nsIObserver
, public nsIRunnable
{};
106 static_assert(std::is_same_v
<ScriptableInterfaceType
<MultiScriptableInterface
>,
108 "Concrete type with multiple scriptable interfaces falls back");
109 } // namespace binding_detail
110 } // namespace mozilla::dom