Merge mozilla-central to autoland. a=merge CLOSED TREE
[gecko.git] / dom / bindings / ToJSValue.cpp
blob73fc7b1e33487a725d863215cb6365d6324c4ca4
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,
28 aValue)) {
29 return false;
32 if (sharedBuffer) {
33 NS_ADDREF(sharedBuffer);
36 return true;
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());
53 MOZ_ASSERT(
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);
59 return true;
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();
71 if (!bc) {
72 aValue.setNull();
73 return true;
75 JS::Rooted<JSObject*> windowProxy(aCx);
76 if (bc->IsInProcess()) {
77 windowProxy = bc->GetWindowProxy();
78 if (!windowProxy) {
79 nsPIDOMWindowOuter* window = bc->GetDOMWindow();
80 if (!window) {
81 // Torn down enough that we should just return null.
82 aValue.setNull();
83 return true;
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,
94 &windowProxy)) {
95 return false;
97 aValue.setObjectOrNull(windowProxy);
98 return true;
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");
106 static_assert(
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 {};
114 static_assert(
115 std::is_same_v<ScriptableInterfaceType<SingleScriptableInterface>,
116 nsIObserver>,
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>,
120 nsISupports>,
121 "Concrete type with multiple scriptable interfaces falls back");
122 } // namespace binding_detail
123 } // namespace mozilla::dom