michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ michael@0: /* vim: set ts=2 sw=2 et tw=79: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef mozilla_dom_ToJSValue_h michael@0: #define mozilla_dom_ToJSValue_h michael@0: michael@0: #include "mozilla/TypeTraits.h" michael@0: #include "mozilla/Assertions.h" michael@0: #include "mozilla/dom/BindingUtils.h" michael@0: #include "mozilla/dom/TypedArray.h" michael@0: #include "jsapi.h" michael@0: #include "nsISupports.h" michael@0: #include "nsTArray.h" michael@0: #include "nsWrapperCache.h" michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: // If ToJSValue returns false, it must set an exception on the michael@0: // JSContext. michael@0: michael@0: // Accept strings. michael@0: bool michael@0: ToJSValue(JSContext* aCx, michael@0: const nsAString& aArgument, michael@0: JS::MutableHandle aValue); michael@0: michael@0: // Accept booleans. michael@0: inline bool michael@0: ToJSValue(JSContext* aCx, michael@0: bool aArgument, michael@0: JS::MutableHandle aValue) michael@0: { michael@0: // Make sure we're called in a compartment michael@0: MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx)); michael@0: michael@0: aValue.setBoolean(aArgument); michael@0: return true; michael@0: } michael@0: michael@0: // Accept integer types michael@0: inline bool michael@0: ToJSValue(JSContext* aCx, michael@0: int32_t aArgument, michael@0: JS::MutableHandle aValue) michael@0: { michael@0: // Make sure we're called in a compartment michael@0: MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx)); michael@0: michael@0: aValue.setInt32(aArgument); michael@0: return true; michael@0: } michael@0: michael@0: // The uint32_t version is disabled for now because on the super-old b2g michael@0: // compiler nsresult and uint32_t are the same type. If someone needs this at michael@0: // some point we'll need to figure out how to make it work (e.g. by switching to michael@0: // traits structs and using the trick IPC's ParamTraits uses, where a traits michael@0: // struct templated on the type inherits from a base traits struct of some sort, michael@0: // templated on the same type, or something). Maybe b2g will update to a modern michael@0: // compiler before that happens.... michael@0: #if 0 michael@0: inline bool michael@0: ToJSValue(JSContext* aCx, michael@0: uint32_t aArgument, michael@0: JS::MutableHandle aValue) michael@0: { michael@0: // Make sure we're called in a compartment michael@0: MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx)); michael@0: michael@0: aValue.setNumber(aArgument); michael@0: return true; michael@0: } michael@0: #endif michael@0: michael@0: inline bool michael@0: ToJSValue(JSContext* aCx, michael@0: int64_t aArgument, michael@0: JS::MutableHandle aValue) michael@0: { michael@0: // Make sure we're called in a compartment michael@0: MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx)); michael@0: michael@0: aValue.setNumber(double(aArgument)); michael@0: return true; michael@0: } michael@0: michael@0: inline bool michael@0: ToJSValue(JSContext* aCx, michael@0: uint64_t aArgument, michael@0: JS::MutableHandle aValue) michael@0: { michael@0: // Make sure we're called in a compartment michael@0: MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx)); michael@0: michael@0: aValue.setNumber(double(aArgument)); michael@0: return true; michael@0: } michael@0: michael@0: // accept floating point types michael@0: inline bool michael@0: ToJSValue(JSContext* aCx, michael@0: float aArgument, michael@0: JS::MutableHandle aValue) michael@0: { michael@0: // Make sure we're called in a compartment michael@0: MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx)); michael@0: michael@0: aValue.setNumber(aArgument); michael@0: return true; michael@0: } michael@0: michael@0: inline bool michael@0: ToJSValue(JSContext* aCx, michael@0: double aArgument, michael@0: JS::MutableHandle aValue) michael@0: { michael@0: // Make sure we're called in a compartment michael@0: MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx)); michael@0: michael@0: aValue.setNumber(aArgument); michael@0: return true; michael@0: } michael@0: michael@0: // Accept objects that inherit from nsWrapperCache and nsISupports (e.g. most michael@0: // DOM objects). michael@0: template michael@0: typename EnableIf::value && michael@0: IsBaseOf::value, bool>::Type michael@0: ToJSValue(JSContext* aCx, michael@0: T& aArgument, michael@0: JS::MutableHandle aValue) michael@0: { michael@0: // Make sure we're called in a compartment michael@0: MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx)); michael@0: // Make sure non-webidl objects don't sneak in here michael@0: MOZ_ASSERT(aArgument.IsDOMBinding()); michael@0: michael@0: return WrapNewBindingObject(aCx, aArgument, aValue); michael@0: } michael@0: michael@0: // Accept typed arrays built from appropriate nsTArray values michael@0: template michael@0: typename EnableIf::value, bool>::Type michael@0: ToJSValue(JSContext* aCx, michael@0: const TypedArrayCreator& aArgument, michael@0: JS::MutableHandle aValue) michael@0: { michael@0: // Make sure we're called in a compartment michael@0: MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx)); michael@0: michael@0: JSObject* obj = aArgument.Create(aCx); michael@0: if (!obj) { michael@0: return false; michael@0: } michael@0: aValue.setObject(*obj); michael@0: return true; michael@0: } michael@0: michael@0: // We don't want to include nsContentUtils here, so use a helper michael@0: // function for the nsISupports case. michael@0: namespace tojsvalue_detail { michael@0: bool michael@0: ISupportsToJSValue(JSContext* aCx, michael@0: nsISupports* aArgument, michael@0: JS::MutableHandle aValue); michael@0: } // namespace tojsvalue_detail michael@0: michael@0: // Accept objects that inherit from nsISupports but not nsWrapperCache (e.g. michael@0: // nsIDOMFile). michael@0: template michael@0: typename EnableIf::value && michael@0: IsBaseOf::value, bool>::Type michael@0: ToJSValue(JSContext* aCx, michael@0: T& aArgument, michael@0: JS::MutableHandle aValue) michael@0: { michael@0: // Make sure we're called in a compartment michael@0: MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx)); michael@0: michael@0: return tojsvalue_detail::ISupportsToJSValue(aCx, &aArgument, aValue); michael@0: } michael@0: michael@0: // Accept nsRefPtr/nsCOMPtr michael@0: template michael@0: bool michael@0: ToJSValue(JSContext* aCx, michael@0: const nsCOMPtr& aArgument, michael@0: JS::MutableHandle aValue) michael@0: { michael@0: return ToJSValue(aCx, *aArgument.get(), aValue); michael@0: } michael@0: michael@0: template michael@0: bool michael@0: ToJSValue(JSContext* aCx, michael@0: const nsRefPtr& aArgument, michael@0: JS::MutableHandle aValue) michael@0: { michael@0: return ToJSValue(aCx, *aArgument.get(), aValue); michael@0: } michael@0: michael@0: // Accept WebIDL dictionaries michael@0: template michael@0: typename EnableIf::value, bool>::Type michael@0: ToJSValue(JSContext* aCx, michael@0: const T& aArgument, michael@0: JS::MutableHandle aValue) michael@0: { michael@0: return aArgument.ToObject(aCx, aValue); michael@0: } michael@0: michael@0: // Accept existing JS values (which may not be same-compartment with us michael@0: inline bool michael@0: ToJSValue(JSContext* aCx, JS::Handle aArgument, michael@0: JS::MutableHandle aValue) michael@0: { michael@0: aValue.set(aArgument); michael@0: return MaybeWrapValue(aCx, aValue); michael@0: } michael@0: michael@0: // Accept nsresult, for use in rejections, and create an XPCOM michael@0: // exception object representing that nsresult. michael@0: bool michael@0: ToJSValue(JSContext* aCx, michael@0: nsresult aArgument, michael@0: JS::MutableHandle aValue); michael@0: michael@0: // Accept arrays of other things we accept michael@0: template michael@0: bool michael@0: ToJSValue(JSContext* aCx, michael@0: T* aArguments, michael@0: size_t aLength, michael@0: JS::MutableHandle aValue) michael@0: { michael@0: // Make sure we're called in a compartment michael@0: MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx)); michael@0: michael@0: JS::AutoValueVector v(aCx); michael@0: if (!v.resize(aLength)) { michael@0: return false; michael@0: } michael@0: for (size_t i = 0; i < aLength; ++i) { michael@0: if (!ToJSValue(aCx, aArguments[i], v.handleAt(i))) { michael@0: return false; michael@0: } michael@0: } michael@0: JSObject* arrayObj = JS_NewArrayObject(aCx, v); michael@0: if (!arrayObj) { michael@0: return false; michael@0: } michael@0: aValue.setObject(*arrayObj); michael@0: return true; michael@0: } michael@0: michael@0: template michael@0: bool michael@0: ToJSValue(JSContext* aCx, michael@0: const nsTArray& aArgument, michael@0: JS::MutableHandle aValue) michael@0: { michael@0: return ToJSValue(aCx, aArgument.Elements(), michael@0: aArgument.Length(), aValue); michael@0: } michael@0: michael@0: template michael@0: bool michael@0: ToJSValue(JSContext* aCx, michael@0: const FallibleTArray& aArgument, michael@0: JS::MutableHandle aValue) michael@0: { michael@0: return ToJSValue(aCx, aArgument.Elements(), michael@0: aArgument.Length(), aValue); michael@0: } michael@0: michael@0: template michael@0: bool michael@0: ToJSValue(JSContext* aCx, michael@0: const T(&aArgument)[N], michael@0: JS::MutableHandle aValue) michael@0: { michael@0: return ToJSValue(aCx, aArgument, N, aValue); michael@0: } michael@0: michael@0: } // namespace dom michael@0: } // namespace mozilla michael@0: michael@0: #endif /* mozilla_dom_ToJSValue_h */