summaryrefslogtreecommitdiffstats
path: root/dom/bindings/ToJSValue.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/bindings/ToJSValue.cpp')
-rw-r--r--dom/bindings/ToJSValue.cpp123
1 files changed, 123 insertions, 0 deletions
diff --git a/dom/bindings/ToJSValue.cpp b/dom/bindings/ToJSValue.cpp
new file mode 100644
index 0000000000..73fc7b1e33
--- /dev/null
+++ b/dom/bindings/ToJSValue.cpp
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/ToJSValue.h"
+#include "mozilla/dom/DOMException.h"
+#include "mozilla/dom/Exceptions.h"
+#include "mozilla/dom/Promise.h"
+#include "mozilla/dom/WindowProxyHolder.h"
+#include "nsAString.h"
+#include "nsContentUtils.h"
+#include "nsStringBuffer.h"
+#include "xpcpublic.h"
+
+namespace mozilla::dom {
+
+bool ToJSValue(JSContext* aCx, const nsAString& aArgument,
+ JS::MutableHandle<JS::Value> aValue) {
+ // Make sure we're called in a compartment
+ MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
+
+ // XXXkhuey I'd love to use xpc::NonVoidStringToJsval here, but it requires
+ // a non-const nsAString for silly reasons.
+ nsStringBuffer* sharedBuffer;
+ if (!XPCStringConvert::ReadableToJSVal(aCx, aArgument, &sharedBuffer,
+ aValue)) {
+ return false;
+ }
+
+ if (sharedBuffer) {
+ NS_ADDREF(sharedBuffer);
+ }
+
+ return true;
+}
+
+bool ToJSValue(JSContext* aCx, const nsACString& aArgument,
+ JS::MutableHandle<JS::Value> aValue) {
+ return UTF8StringToJsval(aCx, aArgument, aValue);
+}
+
+bool ToJSValue(JSContext* aCx, nsresult aArgument,
+ JS::MutableHandle<JS::Value> aValue) {
+ RefPtr<Exception> exception = CreateException(aArgument);
+ return ToJSValue(aCx, exception, aValue);
+}
+
+bool ToJSValue(JSContext* aCx, ErrorResult&& aArgument,
+ JS::MutableHandle<JS::Value> aValue) {
+ MOZ_ASSERT(aArgument.Failed());
+ MOZ_ASSERT(
+ !aArgument.IsUncatchableException(),
+ "Doesn't make sense to convert uncatchable exception to a JS value!");
+ MOZ_ALWAYS_TRUE(aArgument.MaybeSetPendingException(aCx));
+ MOZ_ALWAYS_TRUE(JS_GetPendingException(aCx, aValue));
+ JS_ClearPendingException(aCx);
+ return true;
+}
+
+bool ToJSValue(JSContext* aCx, Promise& aArgument,
+ JS::MutableHandle<JS::Value> aValue) {
+ aValue.setObject(*aArgument.PromiseObj());
+ return MaybeWrapObjectValue(aCx, aValue);
+}
+
+bool ToJSValue(JSContext* aCx, const WindowProxyHolder& aArgument,
+ JS::MutableHandle<JS::Value> aValue) {
+ BrowsingContext* bc = aArgument.get();
+ if (!bc) {
+ aValue.setNull();
+ return true;
+ }
+ JS::Rooted<JSObject*> windowProxy(aCx);
+ if (bc->IsInProcess()) {
+ windowProxy = bc->GetWindowProxy();
+ if (!windowProxy) {
+ nsPIDOMWindowOuter* window = bc->GetDOMWindow();
+ if (!window) {
+ // Torn down enough that we should just return null.
+ aValue.setNull();
+ return true;
+ }
+ if (!window->EnsureInnerWindow()) {
+ return Throw(aCx, NS_ERROR_UNEXPECTED);
+ }
+ windowProxy = bc->GetWindowProxy();
+ }
+ return ToJSValue(aCx, windowProxy, aValue);
+ }
+
+ if (!GetRemoteOuterWindowProxy(aCx, bc, /* aTransplantTo = */ nullptr,
+ &windowProxy)) {
+ return false;
+ }
+ aValue.setObjectOrNull(windowProxy);
+ return true;
+}
+
+// Static assertion tests for the `binding_detail::ScriptableInterfaceType`
+// helper template, used by `ToJSValue`.
+namespace binding_detail {
+static_assert(std::is_same_v<ScriptableInterfaceType<nsISupports>, nsISupports>,
+ "nsISupports works with ScriptableInterfaceType");
+static_assert(
+ std::is_same_v<ScriptableInterfaceType<nsIGlobalObject>, nsISupports>,
+ "non-scriptable interfaces get a fallback");
+static_assert(std::is_same_v<ScriptableInterfaceType<nsIObserver>, nsIObserver>,
+ "scriptable interfaces should get the correct type");
+static_assert(std::is_same_v<ScriptableInterfaceType<nsIRunnable>, nsIRunnable>,
+ "scriptable interfaces should get the correct type");
+class SingleScriptableInterface : public nsIObserver {};
+static_assert(
+ std::is_same_v<ScriptableInterfaceType<SingleScriptableInterface>,
+ nsIObserver>,
+ "Concrete type with one scriptable interface picks the correct interface");
+class MultiScriptableInterface : public nsIObserver, public nsIRunnable {};
+static_assert(std::is_same_v<ScriptableInterfaceType<MultiScriptableInterface>,
+ nsISupports>,
+ "Concrete type with multiple scriptable interfaces falls back");
+} // namespace binding_detail
+} // namespace mozilla::dom