diff options
Diffstat (limited to 'widget/android/NativeJSContainer.cpp')
-rw-r--r-- | widget/android/NativeJSContainer.cpp | 881 |
1 files changed, 0 insertions, 881 deletions
diff --git a/widget/android/NativeJSContainer.cpp b/widget/android/NativeJSContainer.cpp deleted file mode 100644 index b8c434656..000000000 --- a/widget/android/NativeJSContainer.cpp +++ /dev/null @@ -1,881 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- - * 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 "NativeJSContainer.h" - -#include <jni.h> - -#include "Bundle.h" -#include "GeneratedJNINatives.h" -#include "MainThreadUtils.h" -#include "jsapi.h" -#include "nsJSUtils.h" - -#include <mozilla/Vector.h> -#include <mozilla/jni/Accessors.h> -#include <mozilla/jni/Refs.h> -#include <mozilla/jni/Utils.h> - -/** - * NativeJSContainer.cpp implements the native methods in both - * NativeJSContainer and NativeJSObject, using JSAPI to retrieve values from a - * JSObject and using JNI to return those values to Java code. - */ - -namespace mozilla { -namespace widget { - -namespace { - -bool CheckThread() -{ - if (!NS_IsMainThread()) { - jni::ThrowException("java/lang/IllegalThreadStateException", - "Not on Gecko thread"); - return false; - } - return true; -} - -template<class C, typename T> bool -CheckJNIArgument(const jni::Ref<C, T>& arg) -{ - if (!arg) { - jni::ThrowException("java/lang/IllegalArgumentException", - "Null argument"); - } - return !!arg; -} - -nsresult -CheckSDKCall(nsresult rv) -{ - if (NS_FAILED(rv)) { - jni::ThrowException("java/lang/UnsupportedOperationException", - "SDK JNI call failed"); - } - return rv; -} - -// Convert a JNI string to a char16_t string that JSAPI expects. -class JSJNIString final -{ - JNIEnv* const mEnv; - jni::String::Param mJNIString; - const char16_t* const mJSString; - -public: - JSJNIString(JNIEnv* env, jni::String::Param str) - : mEnv(env) - , mJNIString(str) - , mJSString(!str ? nullptr : reinterpret_cast<const char16_t*>( - mEnv->GetStringChars(str.Get(), nullptr))) - {} - - ~JSJNIString() { - if (mJNIString) { - mEnv->ReleaseStringChars(mJNIString.Get(), - reinterpret_cast<const jchar*>(mJSString)); - } - } - - operator const char16_t*() const { - return mJSString; - } - - size_t Length() const { - return static_cast<size_t>(mEnv->GetStringLength(mJNIString.Get())); - } -}; - -} // namepsace - -class NativeJSContainerImpl final - : public NativeJSObject::Natives<NativeJSContainerImpl> - , public NativeJSContainer::Natives<NativeJSContainerImpl> -{ - typedef NativeJSContainerImpl Self; - typedef NativeJSContainer::Natives<NativeJSContainerImpl> ContainerBase; - typedef NativeJSObject::Natives<NativeJSContainerImpl> ObjectBase; - - typedef JS::PersistentRooted<JSObject*> PersistentObject; - - JNIEnv* const mEnv; - // Context that the object is valid in - JSContext* const mJSContext; - // Root JS object - PersistentObject mJSObject; - // Children objects - Vector<NativeJSObject::GlobalRef, 0> mChildren; - - bool CheckObject() const - { - if (!mJSObject) { - jni::ThrowException("java/lang/NullPointerException", - "Null JSObject"); - } - return !!mJSObject; - } - - bool CheckJSCall(bool result) const - { - if (!result) { - JS_ClearPendingException(mJSContext); - jni::ThrowException("java/lang/UnsupportedOperationException", - "JSAPI call failed"); - } - return result; - } - - // Check that a JS Value contains a particular property type as indicaed by - // the property's InValue method (e.g. StringProperty::InValue). - bool CheckProperty(bool (Self::*InValue)(JS::HandleValue) const, - JS::HandleValue val) const - { - if (!(this->*InValue)(val)) { - // XXX this can happen when converting a double array inside a - // Bundle, because double arrays can be misidentified as an int - // array. The workaround is to add a dummy first element to the - // array that is a floating point value, i.e. [0.5, ...]. - jni::ThrowException( - "org/mozilla/gecko/util/NativeJSObject$InvalidPropertyException", - "Property type mismatch"); - return false; - } - return true; - } - - // Primitive properties - - template<bool (JS::Value::*IsType)() const> bool - PrimitiveInValue(JS::HandleValue val) const - { - return (static_cast<const JS::Value&>(val).*IsType)(); - } - - template<typename U, U (JS::Value::*ToType)() const> U - PrimitiveFromValue(JS::HandleValue val) const - { - return (static_cast<const JS::Value&>(val).*ToType)(); - } - - template<class Prop> typename Prop::NativeArray - PrimitiveNewArray(JS::HandleObject array, size_t length) const - { - typedef typename Prop::JNIType JNIType; - - // Fill up a temporary buffer for our array, then use - // JNIEnv::Set*ArrayRegion to fill out array in one go. - - UniquePtr<JNIType[]> buffer = MakeUnique<JNIType[]>(length); - for (size_t i = 0; i < length; i++) { - JS::RootedValue elem(mJSContext); - if (!CheckJSCall(JS_GetElement(mJSContext, array, i, &elem)) || - !CheckProperty(Prop::InValue, elem)) { - return nullptr; - } - buffer[i] = JNIType((this->*Prop::FromValue)(elem)); - } - auto jarray = Prop::NativeArray::Adopt( - mEnv, (mEnv->*Prop::NewJNIArray)(length)); - if (!jarray) { - return nullptr; - } - (mEnv->*Prop::SetJNIArrayRegion)( - jarray.Get(), 0, length, buffer.get()); - if (mEnv->ExceptionCheck()) { - return nullptr; - } - return jarray; - } - - template<typename U, typename UA, typename V, typename VA, - bool (JS::Value::*IsType)() const, - U (JS::Value::*ToType)() const, - VA (JNIEnv::*NewArray_)(jsize), - void (JNIEnv::*SetArrayRegion_)(VA, jsize, jsize, const V*)> - struct PrimitiveProperty - { - // C++ type for a primitive property (e.g. bool) - typedef U NativeType; - // C++ type for the fallback value used in opt* methods - typedef U NativeFallback; - // Type for an array of the primitive type (e.g. BooleanArray::LocalRef) - typedef typename UA::LocalRef NativeArray; - // Type for the fallback value used in opt*Array methods - typedef const typename UA::Ref ArrayFallback; - // JNI type (e.g. jboolean) - typedef V JNIType; - - // JNIEnv function to create a new JNI array of the primiive type - typedef decltype(NewArray_) NewJNIArray_t; - static constexpr NewJNIArray_t NewJNIArray = NewArray_; - - // JNIEnv function to fill a JNI array of the primiive type - typedef decltype(SetArrayRegion_) SetJNIArrayRegion_t; - static constexpr SetJNIArrayRegion_t SetJNIArrayRegion = SetArrayRegion_; - - // Function to determine if a JS Value contains the primitive type - typedef decltype(&Self::PrimitiveInValue<IsType>) InValue_t; - static constexpr InValue_t InValue = &Self::PrimitiveInValue<IsType>; - - // Function to convert a JS Value to the primitive type - typedef decltype(&Self::PrimitiveFromValue<U, ToType>) FromValue_t; - static constexpr FromValue_t FromValue - = &Self::PrimitiveFromValue<U, ToType>; - - // Function to convert a JS array to a JNI array - typedef decltype(&Self::PrimitiveNewArray<PrimitiveProperty>) NewArray_t; - static constexpr NewArray_t NewArray - = &Self::PrimitiveNewArray<PrimitiveProperty>; - }; - - // String properties - - bool StringInValue(JS::HandleValue val) const - { - return val.isString(); - } - - jni::String::LocalRef - StringFromValue(const JS::HandleString str) const - { - nsAutoJSString autoStr; - if (!CheckJSCall(autoStr.init(mJSContext, str))) { - return nullptr; - } - // StringParam can automatically convert a nsString to jstring. - return jni::StringParam(autoStr, mEnv); - } - - jni::String::LocalRef - StringFromValue(JS::HandleValue val) - { - const JS::RootedString str(mJSContext, val.toString()); - return StringFromValue(str); - } - - // Bundle properties - - sdk::Bundle::LocalRef - BundleFromValue(const JS::HandleObject obj) - { - JS::Rooted<JS::IdVector> ids(mJSContext, JS::IdVector(mJSContext)); - if (!CheckJSCall(JS_Enumerate(mJSContext, obj, &ids))) { - return nullptr; - } - - const size_t length = ids.length(); - sdk::Bundle::LocalRef newBundle(mEnv); - NS_ENSURE_SUCCESS(CheckSDKCall( - sdk::Bundle::New(length, &newBundle)), nullptr); - - // Iterate through each property of the JS object. For each property, - // determine its type from a list of supported types, and convert that - // proeprty to the supported type. - - for (size_t i = 0; i < ids.length(); i++) { - const JS::RootedId id(mJSContext, ids[i]); - JS::RootedValue idVal(mJSContext); - if (!CheckJSCall(JS_IdToValue(mJSContext, id, &idVal))) { - return nullptr; - } - - const JS::RootedString idStr(mJSContext, - JS::ToString(mJSContext, idVal)); - if (!CheckJSCall(!!idStr)) { - return nullptr; - } - - jni::String::LocalRef name = StringFromValue(idStr); - JS::RootedValue val(mJSContext); - if (!name || - !CheckJSCall(JS_GetPropertyById(mJSContext, obj, id, &val))) { - return nullptr; - } - -#define PUT_IN_BUNDLE_IF_TYPE_IS(TYPE) \ - if ((this->*TYPE##Property::InValue)(val)) { \ - auto jval = (this->*TYPE##Property::FromValue)(val); \ - if (mEnv->ExceptionCheck()) { \ - return nullptr; \ - } \ - NS_ENSURE_SUCCESS(CheckSDKCall( \ - newBundle->Put##TYPE(name, jval)), nullptr); \ - continue; \ - } \ - ((void) 0) // Accommodate trailing semicolon. - - // Scalar values are faster to check, so check them first. - PUT_IN_BUNDLE_IF_TYPE_IS(Boolean); - // Int can be casted to double, so check int first. - PUT_IN_BUNDLE_IF_TYPE_IS(Int); - PUT_IN_BUNDLE_IF_TYPE_IS(Double); - PUT_IN_BUNDLE_IF_TYPE_IS(String); - // There's no "putObject", so don't check ObjectProperty - - // Check for array types if scalar checks all failed. - // XXX empty arrays are treated as boolean arrays. Workaround is - // to always have a dummy element to create a non-empty array. - PUT_IN_BUNDLE_IF_TYPE_IS(BooleanArray); - // XXX because we only check the first element of an array, - // a double array can potentially be seen as an int array. - // When that happens, the Bundle conversion will fail. - PUT_IN_BUNDLE_IF_TYPE_IS(IntArray); - PUT_IN_BUNDLE_IF_TYPE_IS(DoubleArray); - PUT_IN_BUNDLE_IF_TYPE_IS(StringArray); - // There's no "putObjectArray", so don't check ObjectArrayProperty - // There's no "putBundleArray", so don't check BundleArrayProperty - - // Use Bundle as the default catch-all for objects - PUT_IN_BUNDLE_IF_TYPE_IS(Bundle); - -#undef PUT_IN_BUNDLE_IF_TYPE_IS - - // We tried all supported types; just bail. - jni::ThrowException("java/lang/UnsupportedOperationException", - "Unsupported property type"); - return nullptr; - } - return jni::Object::LocalRef::Adopt(newBundle.Env(), - newBundle.Forget()); - } - - sdk::Bundle::LocalRef - BundleFromValue(JS::HandleValue val) - { - if (val.isNull()) { - return nullptr; - } - JS::RootedObject object(mJSContext, &val.toObject()); - return BundleFromValue(object); - } - - // Object properties - - bool ObjectInValue(JS::HandleValue val) const - { - return val.isObjectOrNull(); - } - - NativeJSObject::LocalRef - ObjectFromValue(JS::HandleValue val) - { - if (val.isNull()) { - return nullptr; - } - JS::RootedObject object(mJSContext, &val.toObject()); - return CreateChild(object); - } - - template<class Prop> typename Prop::NativeArray - ObjectNewArray(JS::HandleObject array, size_t length) - { - auto jarray = Prop::NativeArray::Adopt(mEnv, mEnv->NewObjectArray( - length, typename Prop::ClassType::Context().ClassRef(), - nullptr)); - if (!jarray) { - return nullptr; - } - - // For object arrays, we have to set each element separately. - for (size_t i = 0; i < length; i++) { - JS::RootedValue elem(mJSContext); - if (!CheckJSCall(JS_GetElement(mJSContext, array, i, &elem)) || - !CheckProperty(Prop::InValue, elem)) { - return nullptr; - } - mEnv->SetObjectArrayElement( - jarray.Get(), i, (this->*Prop::FromValue)(elem).Get()); - if (mEnv->ExceptionCheck()) { - return nullptr; - } - } - return jarray; - } - - template<class Class, - bool (Self::*InValue_)(JS::HandleValue) const, - typename Class::LocalRef (Self::*FromValue_)(JS::HandleValue)> - struct BaseObjectProperty - { - // JNI class for the object type (e.g. jni::String) - typedef Class ClassType; - - // See comments in PrimitiveProperty. - typedef typename ClassType::LocalRef NativeType; - typedef const typename ClassType::Ref NativeFallback; - typedef typename jni::ObjectArray::LocalRef NativeArray; - typedef const jni::ObjectArray::Ref ArrayFallback; - - typedef decltype(InValue_) InValue_t; - static constexpr InValue_t InValue = InValue_; - - typedef decltype(FromValue_) FromValue_t; - static constexpr FromValue_t FromValue = FromValue_; - - typedef decltype(&Self::ObjectNewArray<BaseObjectProperty>) NewArray_t; - static constexpr NewArray_t NewArray - = &Self::ObjectNewArray<BaseObjectProperty>; - }; - - // Array properties - - template<class Prop> bool - ArrayInValue(JS::HandleValue val) const - { - if (!val.isObject()) { - return false; - } - JS::RootedObject obj(mJSContext, &val.toObject()); - bool isArray; - uint32_t length = 0; - if (!JS_IsArrayObject(mJSContext, obj, &isArray) || - !isArray || - !JS_GetArrayLength(mJSContext, obj, &length)) { - JS_ClearPendingException(mJSContext); - return false; - } - if (!length) { - // Empty arrays are always okay. - return true; - } - // We only check to see the first element is the target type. If the - // array has mixed types, we'll throw an error during actual conversion. - JS::RootedValue element(mJSContext); - if (!JS_GetElement(mJSContext, obj, 0, &element)) { - JS_ClearPendingException(mJSContext); - return false; - } - return (this->*Prop::InValue)(element); - } - - template<class Prop> typename Prop::NativeArray - ArrayFromValue(JS::HandleValue val) - { - JS::RootedObject obj(mJSContext, &val.toObject()); - uint32_t length = 0; - if (!CheckJSCall(JS_GetArrayLength(mJSContext, obj, &length))) { - return nullptr; - } - return (this->*Prop::NewArray)(obj, length); - } - - template<class Prop> - struct ArrayProperty - { - // See comments in PrimitiveProperty. - typedef typename Prop::NativeArray NativeType; - typedef typename Prop::ArrayFallback NativeFallback; - - typedef decltype(&Self::ArrayInValue<Prop>) InValue_t; - static constexpr InValue_t InValue - = &Self::ArrayInValue<Prop>; - - typedef decltype(&Self::ArrayFromValue<Prop>) FromValue_t; - static constexpr FromValue_t FromValue - = &Self::ArrayFromValue<Prop>; - }; - - // "Has" property is a special property type that is used to implement - // NativeJSObject.has, by returning true from InValue and FromValue for - // every existing property, and having false as the fallback value for - // when a property doesn't exist. - - bool HasValue(JS::HandleValue val) const - { - return true; - } - - struct HasProperty - { - // See comments in PrimitiveProperty. - typedef bool NativeType; - typedef bool NativeFallback; - - typedef decltype(&Self::HasValue) HasValue_t; - static constexpr HasValue_t InValue = &Self::HasValue; - static constexpr HasValue_t FromValue = &Self::HasValue; - }; - - // Statically cast from bool to jboolean (unsigned char); it works - // since false and JNI_FALSE have the same value (0), and true and - // JNI_TRUE have the same value (1). - typedef PrimitiveProperty< - bool, jni::BooleanArray, jboolean, jbooleanArray, - &JS::Value::isBoolean, &JS::Value::toBoolean, - &JNIEnv::NewBooleanArray, &JNIEnv::SetBooleanArrayRegion> - BooleanProperty; - - typedef PrimitiveProperty< - double, jni::DoubleArray, jdouble, jdoubleArray, - &JS::Value::isNumber, &JS::Value::toNumber, - &JNIEnv::NewDoubleArray, &JNIEnv::SetDoubleArrayRegion> - DoubleProperty; - - typedef PrimitiveProperty< - int32_t, jni::IntArray, jint, jintArray, - &JS::Value::isInt32, &JS::Value::toInt32, - &JNIEnv::NewIntArray, &JNIEnv::SetIntArrayRegion> - IntProperty; - - typedef BaseObjectProperty< - jni::String, &Self::StringInValue, &Self::StringFromValue> - StringProperty; - - typedef BaseObjectProperty< - sdk::Bundle, &Self::ObjectInValue, &Self::BundleFromValue> - BundleProperty; - - typedef BaseObjectProperty< - NativeJSObject, &Self::ObjectInValue, &Self::ObjectFromValue> - ObjectProperty; - - typedef ArrayProperty<BooleanProperty> BooleanArrayProperty; - typedef ArrayProperty<DoubleProperty> DoubleArrayProperty; - typedef ArrayProperty<IntProperty> IntArrayProperty; - typedef ArrayProperty<StringProperty> StringArrayProperty; - typedef ArrayProperty<BundleProperty> BundleArrayProperty; - typedef ArrayProperty<ObjectProperty> ObjectArrayProperty; - - template<class Prop> - typename Prop::NativeType - GetProperty(jni::String::Param name, - typename Prop::NativeFallback* fallback = nullptr) - { - if (!CheckThread() || !CheckObject()) { - return typename Prop::NativeType(); - } - - const JSJNIString nameStr(mEnv, name); - JS::RootedValue val(mJSContext); - - if (!CheckJNIArgument(name) || - !CheckJSCall(JS_GetUCProperty( - mJSContext, mJSObject, nameStr, nameStr.Length(), &val))) { - return typename Prop::NativeType(); - } - - // Strictly, null is different from undefined in JS. However, in - // practice, null is often used to indicate a property doesn't exist in - // the same manner as undefined. Therefore, we treat null in the same - // way as undefined when checking property existence (bug 1014965). - if (val.isUndefined() || val.isNull()) { - if (fallback) { - return mozilla::Move(*fallback); - } - jni::ThrowException( - "org/mozilla/gecko/util/NativeJSObject$InvalidPropertyException", - "Property does not exist"); - return typename Prop::NativeType(); - } - - if (!CheckProperty(Prop::InValue, val)) { - return typename Prop::NativeType(); - } - return (this->*Prop::FromValue)(val); - } - - NativeJSObject::LocalRef CreateChild(JS::HandleObject object) - { - auto instance = NativeJSObject::New(); - mozilla::UniquePtr<NativeJSContainerImpl> impl( - new NativeJSContainerImpl(instance.Env(), mJSContext, object)); - - ObjectBase::AttachNative(instance, mozilla::Move(impl)); - if (!mChildren.append(NativeJSObject::GlobalRef(instance))) { - MOZ_CRASH(); - } - return instance; - } - - NativeJSContainerImpl(JNIEnv* env, JSContext* cx, JS::HandleObject object) - : mEnv(env) - , mJSContext(cx) - , mJSObject(cx, object) - {} - -public: - ~NativeJSContainerImpl() - { - // Dispose of all children on destruction. The children will in turn - // dispose any of their children (i.e. our grandchildren) and so on. - NativeJSObject::LocalRef child(mEnv); - for (size_t i = 0; i < mChildren.length(); i++) { - child = mChildren[i]; - ObjectBase::GetNative(child)->ObjectBase::DisposeNative(child); - } - } - - static NativeJSContainer::LocalRef - CreateInstance(JSContext* cx, JS::HandleObject object) - { - auto instance = NativeJSContainer::New(); - mozilla::UniquePtr<NativeJSContainerImpl> impl( - new NativeJSContainerImpl(instance.Env(), cx, object)); - - ContainerBase::AttachNative(instance, mozilla::Move(impl)); - return instance; - } - - // NativeJSContainer methods - - void DisposeNative(const NativeJSContainer::LocalRef& instance) - { - if (!CheckThread()) { - return; - } - ContainerBase::DisposeNative(instance); - } - - NativeJSContainer::LocalRef Clone() - { - if (!CheckThread()) { - return nullptr; - } - return CreateInstance(mJSContext, mJSObject); - } - - // NativeJSObject methods - - bool GetBoolean(jni::String::Param name) - { - return GetProperty<BooleanProperty>(name); - } - - bool OptBoolean(jni::String::Param name, bool fallback) - { - return GetProperty<BooleanProperty>(name, &fallback); - } - - jni::BooleanArray::LocalRef - GetBooleanArray(jni::String::Param name) - { - return GetProperty<BooleanArrayProperty>(name); - } - - jni::BooleanArray::LocalRef - OptBooleanArray(jni::String::Param name, jni::BooleanArray::Param fallback) - { - return GetProperty<BooleanArrayProperty>(name, &fallback); - } - - jni::Object::LocalRef - GetBundle(jni::String::Param name) - { - return GetProperty<BundleProperty>(name); - } - - jni::Object::LocalRef - OptBundle(jni::String::Param name, jni::Object::Param fallback) - { - // Because the GetProperty expects a sdk::Bundle::Param, - // we have to do conversions here from jni::Object::Param. - const auto& fb = sdk::Bundle::Ref::From(fallback.Get()); - return GetProperty<BundleProperty>(name, &fb); - } - - jni::ObjectArray::LocalRef - GetBundleArray(jni::String::Param name) - { - return GetProperty<BundleArrayProperty>(name); - } - - jni::ObjectArray::LocalRef - OptBundleArray(jni::String::Param name, jni::ObjectArray::Param fallback) - { - return GetProperty<BundleArrayProperty>(name, &fallback); - } - - double GetDouble(jni::String::Param name) - { - return GetProperty<DoubleProperty>(name); - } - - double OptDouble(jni::String::Param name, double fallback) - { - return GetProperty<DoubleProperty>(name, &fallback); - } - - jni::DoubleArray::LocalRef - GetDoubleArray(jni::String::Param name) - { - return GetProperty<DoubleArrayProperty>(name); - } - - jni::DoubleArray::LocalRef - OptDoubleArray(jni::String::Param name, jni::DoubleArray::Param fallback) - { - jni::DoubleArray::LocalRef fb(fallback); - return GetProperty<DoubleArrayProperty>(name, &fb); - } - - int GetInt(jni::String::Param name) - { - return GetProperty<IntProperty>(name); - } - - int OptInt(jni::String::Param name, int fallback) - { - return GetProperty<IntProperty>(name, &fallback); - } - - jni::IntArray::LocalRef - GetIntArray(jni::String::Param name) - { - return GetProperty<IntArrayProperty>(name); - } - - jni::IntArray::LocalRef - OptIntArray(jni::String::Param name, jni::IntArray::Param fallback) - { - jni::IntArray::LocalRef fb(fallback); - return GetProperty<IntArrayProperty>(name, &fb); - } - - NativeJSObject::LocalRef - GetObject(jni::String::Param name) - { - return GetProperty<ObjectProperty>(name); - } - - NativeJSObject::LocalRef - OptObject(jni::String::Param name, NativeJSObject::Param fallback) - { - return GetProperty<ObjectProperty>(name, &fallback); - } - - jni::ObjectArray::LocalRef - GetObjectArray(jni::String::Param name) - { - return GetProperty<ObjectArrayProperty>(name); - } - - jni::ObjectArray::LocalRef - OptObjectArray(jni::String::Param name, jni::ObjectArray::Param fallback) - { - return GetProperty<ObjectArrayProperty>(name, &fallback); - } - - jni::String::LocalRef - GetString(jni::String::Param name) - { - return GetProperty<StringProperty>(name); - } - - jni::String::LocalRef - OptString(jni::String::Param name, jni::String::Param fallback) - { - return GetProperty<StringProperty>(name, &fallback); - } - - jni::ObjectArray::LocalRef - GetStringArray(jni::String::Param name) - { - return GetProperty<StringArrayProperty>(name); - } - - jni::ObjectArray::LocalRef - OptStringArray(jni::String::Param name, jni::ObjectArray::Param fallback) - { - return GetProperty<StringArrayProperty>(name, &fallback); - } - - bool Has(jni::String::Param name) - { - bool no = false; - // Fallback to false indicating no such property. - return GetProperty<HasProperty>(name, &no); - } - - jni::Object::LocalRef ToBundle() - { - if (!CheckThread() || !CheckObject()) { - return nullptr; - } - return BundleFromValue(mJSObject); - } - -private: - static bool AppendJSON(const char16_t* buf, uint32_t len, void* data) - { - static_cast<nsAutoString*>(data)->Append(buf, len); - return true; - } - -public: - jni::String::LocalRef ToString() - { - if (!CheckThread() || !CheckObject()) { - return nullptr; - } - - JS::RootedValue value(mJSContext, JS::ObjectValue(*mJSObject)); - nsAutoString json; - if (!CheckJSCall(JS_Stringify(mJSContext, &value, nullptr, - JS::NullHandleValue, AppendJSON, &json))) { - return nullptr; - } - return jni::StringParam(json, mEnv); - } -}; - - -// Define the "static constexpr" members of our property types (e.g. -// PrimitiveProperty<>::InValue). This is tricky because there are a lot of -// template parameters, so we use macros to make it simpler. - -#define DEFINE_PRIMITIVE_PROPERTY_MEMBER(Name) \ - template<typename U, typename UA, typename V, typename VA, \ - bool (JS::Value::*I)() const, \ - U (JS::Value::*T)() const, \ - VA (JNIEnv::*N)(jsize), \ - void (JNIEnv::*S)(VA, jsize, jsize, const V*)> \ - constexpr typename NativeJSContainerImpl \ - ::PrimitiveProperty<U, UA, V, VA, I, T, N, S>::Name##_t \ - NativeJSContainerImpl::PrimitiveProperty<U, UA, V, VA, I, T, N, S>::Name - -DEFINE_PRIMITIVE_PROPERTY_MEMBER(NewJNIArray); -DEFINE_PRIMITIVE_PROPERTY_MEMBER(SetJNIArrayRegion); -DEFINE_PRIMITIVE_PROPERTY_MEMBER(InValue); -DEFINE_PRIMITIVE_PROPERTY_MEMBER(FromValue); -DEFINE_PRIMITIVE_PROPERTY_MEMBER(NewArray); - -#undef DEFINE_PRIMITIVE_PROPERTY_MEMBER - -#define DEFINE_OBJECT_PROPERTY_MEMBER(Name) \ - template<class C, \ - bool (NativeJSContainerImpl::*I)(JS::HandleValue) const, \ - typename C::LocalRef (NativeJSContainerImpl::*F)(JS::HandleValue)> \ - constexpr typename NativeJSContainerImpl \ - ::BaseObjectProperty<C, I, F>::Name##_t \ - NativeJSContainerImpl::BaseObjectProperty<C, I, F>::Name - -DEFINE_OBJECT_PROPERTY_MEMBER(InValue); -DEFINE_OBJECT_PROPERTY_MEMBER(FromValue); -DEFINE_OBJECT_PROPERTY_MEMBER(NewArray); - -#undef DEFINE_OBJECT_PROPERTY_MEMBER - -template<class P> constexpr typename NativeJSContainerImpl::ArrayProperty<P> - ::InValue_t NativeJSContainerImpl::ArrayProperty<P>::InValue; -template<class P> constexpr typename NativeJSContainerImpl::ArrayProperty<P> - ::FromValue_t NativeJSContainerImpl::ArrayProperty<P>::FromValue; - -constexpr NativeJSContainerImpl::HasProperty::HasValue_t - NativeJSContainerImpl::HasProperty::InValue; -constexpr NativeJSContainerImpl::HasProperty::HasValue_t - NativeJSContainerImpl::HasProperty::FromValue; - - -NativeJSContainer::LocalRef -CreateNativeJSContainer(JSContext* cx, JS::HandleObject object) -{ - return NativeJSContainerImpl::CreateInstance(cx, object); -} - -} // namespace widget -} // namespace mozilla - |