mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 992357 - c. Add primitive array support to NativeJSObject; r=blassey
This commit is contained in:
parent
c5ae95c1bf
commit
b5e09b233d
@ -72,6 +72,18 @@ public:
|
|||||||
env, jBundle, "putString",
|
env, jBundle, "putString",
|
||||||
"(Ljava/lang/String;Ljava/lang/String;)V");
|
"(Ljava/lang/String;Ljava/lang/String;)V");
|
||||||
MOZ_ASSERT(jBundlePutString);
|
MOZ_ASSERT(jBundlePutString);
|
||||||
|
jBundlePutBooleanArray = AndroidBridge::GetMethodID(
|
||||||
|
env, jBundle, "putBooleanArray",
|
||||||
|
"(Ljava/lang/String;[Z)V");
|
||||||
|
MOZ_ASSERT(jBundlePutBooleanArray);
|
||||||
|
jBundlePutDoubleArray = AndroidBridge::GetMethodID(
|
||||||
|
env, jBundle, "putDoubleArray",
|
||||||
|
"(Ljava/lang/String;[D)V");
|
||||||
|
MOZ_ASSERT(jBundlePutDoubleArray);
|
||||||
|
jBundlePutIntArray = AndroidBridge::GetMethodID(
|
||||||
|
env, jBundle, "putIntArray",
|
||||||
|
"(Ljava/lang/String;[I)V");
|
||||||
|
MOZ_ASSERT(jBundlePutIntArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
static jobject CreateInstance(JNIEnv* env, JSContext* cx,
|
static jobject CreateInstance(JNIEnv* env, JSContext* cx,
|
||||||
@ -227,6 +239,9 @@ public:
|
|||||||
static jmethodID jBundlePutDouble;
|
static jmethodID jBundlePutDouble;
|
||||||
static jmethodID jBundlePutInt;
|
static jmethodID jBundlePutInt;
|
||||||
static jmethodID jBundlePutString;
|
static jmethodID jBundlePutString;
|
||||||
|
static jmethodID jBundlePutBooleanArray;
|
||||||
|
static jmethodID jBundlePutDoubleArray;
|
||||||
|
static jmethodID jBundlePutIntArray;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static jclass jNativeJSContainer;
|
static jclass jNativeJSContainer;
|
||||||
@ -299,6 +314,9 @@ jmethodID NativeJSContainer::jBundlePutBundle = 0;
|
|||||||
jmethodID NativeJSContainer::jBundlePutDouble = 0;
|
jmethodID NativeJSContainer::jBundlePutDouble = 0;
|
||||||
jmethodID NativeJSContainer::jBundlePutInt = 0;
|
jmethodID NativeJSContainer::jBundlePutInt = 0;
|
||||||
jmethodID NativeJSContainer::jBundlePutString = 0;
|
jmethodID NativeJSContainer::jBundlePutString = 0;
|
||||||
|
jmethodID NativeJSContainer::jBundlePutBooleanArray = 0;
|
||||||
|
jmethodID NativeJSContainer::jBundlePutDoubleArray = 0;
|
||||||
|
jmethodID NativeJSContainer::jBundlePutIntArray = 0;
|
||||||
|
|
||||||
jobject
|
jobject
|
||||||
CreateNativeJSContainer(JNIEnv* env, JSContext* cx, JS::HandleObject object)
|
CreateNativeJSContainer(JNIEnv* env, JSContext* cx, JS::HandleObject object)
|
||||||
@ -360,6 +378,17 @@ CheckJNIArgument(JNIEnv* env, jobject arg)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <bool (*InValue)(JSContext*, JS::HandleValue)> bool
|
||||||
|
CheckProperty(JNIEnv* env, JSContext* cx, JS::HandleValue val) {
|
||||||
|
if (!(*InValue)(cx, val)) {
|
||||||
|
AndroidBridge::ThrowException(env,
|
||||||
|
"java/lang/IllegalArgumentException",
|
||||||
|
"Property type mismatch");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
AppendJSON(const jschar* buf, uint32_t len, void* data)
|
AppendJSON(const jschar* buf, uint32_t len, void* data)
|
||||||
{
|
{
|
||||||
@ -369,13 +398,17 @@ AppendJSON(const jschar* buf, uint32_t len, void* data)
|
|||||||
|
|
||||||
template <typename U, typename V,
|
template <typename U, typename V,
|
||||||
bool (JS::Value::*IsMethod)() const,
|
bool (JS::Value::*IsMethod)() const,
|
||||||
V (JS::Value::*ToMethod)() const>
|
V (JS::Value::*ToMethod)() const,
|
||||||
|
typename UA,
|
||||||
|
UA (JNIEnv::*NewArrayMethod)(jsize),
|
||||||
|
void (JNIEnv::*SetArrayRegionMethod)(UA, jsize, jsize, const U*)>
|
||||||
struct PrimitiveProperty
|
struct PrimitiveProperty
|
||||||
{
|
{
|
||||||
typedef U Type; // JNI type
|
typedef U Type; // JNI type
|
||||||
|
typedef UA ArrayType; // JNI array type
|
||||||
typedef V NativeType; // JSAPI type
|
typedef V NativeType; // JSAPI type
|
||||||
|
|
||||||
static bool InValue(JS::HandleValue val) {
|
static bool InValue(JSContext* cx, JS::HandleValue val) {
|
||||||
return (static_cast<const JS::Value&>(val).*IsMethod)();
|
return (static_cast<const JS::Value&>(val).*IsMethod)();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,25 +417,54 @@ struct PrimitiveProperty
|
|||||||
return static_cast<Type>(
|
return static_cast<Type>(
|
||||||
(static_cast<const JS::Value&>(val).*ToMethod)());
|
(static_cast<const JS::Value&>(val).*ToMethod)());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ArrayType NewArray(JNIEnv* env, jobject instance, JSContext* cx,
|
||||||
|
JS::HandleObject array, size_t length) {
|
||||||
|
ScopedDeleteArray<Type> buffer(new Type[length]);
|
||||||
|
for (size_t i = 0; i < length; i++) {
|
||||||
|
JS::RootedValue elem(cx);
|
||||||
|
if (!CheckJSCall(env, JS_GetElement(cx, array, i, &elem)) ||
|
||||||
|
!CheckProperty<InValue>(env, cx, elem)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
buffer[i] = FromValue(env, instance, cx, elem);
|
||||||
|
}
|
||||||
|
AutoLocalJNIFrame frame(env, 1);
|
||||||
|
ArrayType jarray = (env->*NewArrayMethod)(length);
|
||||||
|
if (!jarray) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
(env->*SetArrayRegionMethod)(jarray, 0, length, buffer);
|
||||||
|
if (env->ExceptionCheck()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return frame.Pop(jarray);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Statically cast from bool to jboolean (unsigned char); it works
|
// Statically cast from bool to jboolean (unsigned char); it works
|
||||||
// since false and JNI_FALSE have the same value (0), and true and
|
// since false and JNI_FALSE have the same value (0), and true and
|
||||||
// JNI_TRUE have the same value (1).
|
// JNI_TRUE have the same value (1).
|
||||||
typedef PrimitiveProperty<jboolean, bool,
|
typedef PrimitiveProperty<jboolean, bool,
|
||||||
&JS::Value::isBoolean, &JS::Value::toBoolean> BooleanProperty;
|
&JS::Value::isBoolean, &JS::Value::toBoolean,
|
||||||
|
jbooleanArray, &JNIEnv::NewBooleanArray,
|
||||||
|
&JNIEnv::SetBooleanArrayRegion> BooleanProperty;
|
||||||
|
|
||||||
typedef PrimitiveProperty<jdouble, double,
|
typedef PrimitiveProperty<jdouble, double,
|
||||||
&JS::Value::isNumber, &JS::Value::toNumber> DoubleProperty;
|
&JS::Value::isNumber, &JS::Value::toNumber,
|
||||||
|
jdoubleArray, &JNIEnv::NewDoubleArray,
|
||||||
|
&JNIEnv::SetDoubleArrayRegion> DoubleProperty;
|
||||||
|
|
||||||
typedef PrimitiveProperty<jint, int32_t,
|
typedef PrimitiveProperty<jint, int32_t,
|
||||||
&JS::Value::isInt32, &JS::Value::toInt32> IntProperty;
|
&JS::Value::isInt32, &JS::Value::toInt32,
|
||||||
|
jintArray, &JNIEnv::NewIntArray,
|
||||||
|
&JNIEnv::SetIntArrayRegion> IntProperty;
|
||||||
|
|
||||||
struct StringProperty
|
struct StringProperty
|
||||||
{
|
{
|
||||||
typedef jstring Type;
|
typedef jstring Type;
|
||||||
|
|
||||||
static bool InValue(JS::HandleValue val) {
|
static bool InValue(JSContext* cx, JS::HandleValue val) {
|
||||||
return val.isString();
|
return val.isString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -434,7 +496,7 @@ struct BaseObjectProperty
|
|||||||
{
|
{
|
||||||
typedef jobject Type;
|
typedef jobject Type;
|
||||||
|
|
||||||
static bool InValue(JS::HandleValue val) {
|
static bool InValue(JSContext* cx, JS::HandleValue val) {
|
||||||
return val.isObjectOrNull();
|
return val.isObjectOrNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -457,11 +519,53 @@ typedef BaseObjectProperty<
|
|||||||
// Returns a Bundle from a JSObject
|
// Returns a Bundle from a JSObject
|
||||||
typedef BaseObjectProperty<GetBundle> BundleProperty;
|
typedef BaseObjectProperty<GetBundle> BundleProperty;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct ArrayProperty
|
||||||
|
{
|
||||||
|
typedef T Base;
|
||||||
|
typedef typename T::ArrayType Type;
|
||||||
|
|
||||||
|
static bool InValue(JSContext* cx, JS::HandleValue val) {
|
||||||
|
if (!val.isObject()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
JS::RootedObject obj(cx, &val.toObject());
|
||||||
|
uint32_t length = 0;
|
||||||
|
if (!JS_IsArrayObject(cx, obj) ||
|
||||||
|
!JS_GetArrayLength(cx, obj, &length)) {
|
||||||
|
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(cx);
|
||||||
|
return JS_GetElement(cx, obj, 0, &element) &&
|
||||||
|
Base::InValue(cx, element);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Type FromValue(JNIEnv* env, jobject instance,
|
||||||
|
JSContext* cx, JS::HandleValue val) {
|
||||||
|
JS::RootedObject obj(cx, &val.toObject());
|
||||||
|
uint32_t length = 0;
|
||||||
|
if (!CheckJSCall(env, JS_GetArrayLength(cx, obj, &length))) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return Base::NewArray(env, instance, cx, obj, length);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef ArrayProperty<BooleanProperty> BooleanArrayProperty;
|
||||||
|
typedef ArrayProperty<DoubleProperty> DoubleArrayProperty;
|
||||||
|
typedef ArrayProperty<IntProperty> IntArrayProperty;
|
||||||
|
|
||||||
struct HasProperty
|
struct HasProperty
|
||||||
{
|
{
|
||||||
typedef jboolean Type;
|
typedef jboolean Type;
|
||||||
|
|
||||||
static bool InValue(JS::HandleValue val) {
|
static bool InValue(JSContext* cx, JS::HandleValue val) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -510,10 +614,7 @@ GetProperty(JNIEnv* env, jobject instance, jstring name,
|
|||||||
}
|
}
|
||||||
return fallback;
|
return fallback;
|
||||||
}
|
}
|
||||||
if (!Property::InValue(val)) {
|
if (!CheckProperty<Property::InValue>(env, cx, val)) {
|
||||||
AndroidBridge::ThrowException(env,
|
|
||||||
"java/lang/IllegalArgumentException",
|
|
||||||
"Property type mismatch");
|
|
||||||
return fallback;
|
return fallback;
|
||||||
}
|
}
|
||||||
return Property::FromValue(env, instance, cx, val);
|
return Property::FromValue(env, instance, cx, val);
|
||||||
@ -562,7 +663,7 @@ GetBundle(JNIEnv* env, jobject instance, JSContext* cx, JS::HandleObject obj)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define PUT_IN_BUNDLE_IF_TYPE_IS(Type) \
|
#define PUT_IN_BUNDLE_IF_TYPE_IS(Type) \
|
||||||
if (Type##Property::InValue(val)) { \
|
if (Type##Property::InValue(cx, val)) { \
|
||||||
env->CallVoidMethod( \
|
env->CallVoidMethod( \
|
||||||
newBundle, \
|
newBundle, \
|
||||||
NativeJSContainer::jBundlePut##Type, \
|
NativeJSContainer::jBundlePut##Type, \
|
||||||
@ -573,11 +674,21 @@ GetBundle(JNIEnv* env, jobject instance, JSContext* cx, JS::HandleObject obj)
|
|||||||
} \
|
} \
|
||||||
((void) 0) // Accommodate trailing semicolon.
|
((void) 0) // Accommodate trailing semicolon.
|
||||||
|
|
||||||
|
// Scalar values are faster to check, so check them first.
|
||||||
PUT_IN_BUNDLE_IF_TYPE_IS(Boolean);
|
PUT_IN_BUNDLE_IF_TYPE_IS(Boolean);
|
||||||
// Int can be casted to double, so check int first.
|
// Int can be casted to double, so check int first.
|
||||||
PUT_IN_BUNDLE_IF_TYPE_IS(Int);
|
PUT_IN_BUNDLE_IF_TYPE_IS(Int);
|
||||||
PUT_IN_BUNDLE_IF_TYPE_IS(Double);
|
PUT_IN_BUNDLE_IF_TYPE_IS(Double);
|
||||||
PUT_IN_BUNDLE_IF_TYPE_IS(String);
|
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.
|
||||||
|
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.
|
||||||
|
PUT_IN_BUNDLE_IF_TYPE_IS(IntArray);
|
||||||
|
PUT_IN_BUNDLE_IF_TYPE_IS(DoubleArray);
|
||||||
|
|
||||||
// Use Bundle as the default catch-all for objects
|
// Use Bundle as the default catch-all for objects
|
||||||
PUT_IN_BUNDLE_IF_TYPE_IS(Bundle);
|
PUT_IN_BUNDLE_IF_TYPE_IS(Bundle);
|
||||||
|
|
||||||
@ -627,14 +738,14 @@ NS_EXPORT jbooleanArray JNICALL
|
|||||||
Java_org_mozilla_gecko_util_NativeJSObject_getBooleanArray(
|
Java_org_mozilla_gecko_util_NativeJSObject_getBooleanArray(
|
||||||
JNIEnv* env, jobject instance, jstring name)
|
JNIEnv* env, jobject instance, jstring name)
|
||||||
{
|
{
|
||||||
return nullptr; // TODO add implementation
|
return GetProperty<BooleanArrayProperty>(env, instance, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_EXPORT jbooleanArray JNICALL
|
NS_EXPORT jbooleanArray JNICALL
|
||||||
Java_org_mozilla_gecko_util_NativeJSObject_optBooleanArray(
|
Java_org_mozilla_gecko_util_NativeJSObject_optBooleanArray(
|
||||||
JNIEnv* env, jobject instance, jstring name, jbooleanArray fallback)
|
JNIEnv* env, jobject instance, jstring name, jbooleanArray fallback)
|
||||||
{
|
{
|
||||||
return nullptr; // TODO add implementation
|
return GetProperty<BooleanArrayProperty>(env, instance, name, FallbackOption::RETURN, fallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_EXPORT jobject JNICALL
|
NS_EXPORT jobject JNICALL
|
||||||
@ -681,14 +792,14 @@ NS_EXPORT jdoubleArray JNICALL
|
|||||||
Java_org_mozilla_gecko_util_NativeJSObject_getDoubleArray(
|
Java_org_mozilla_gecko_util_NativeJSObject_getDoubleArray(
|
||||||
JNIEnv* env, jobject instance, jstring name)
|
JNIEnv* env, jobject instance, jstring name)
|
||||||
{
|
{
|
||||||
return nullptr; // TODO add implementation
|
return GetProperty<DoubleArrayProperty>(env, instance, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_EXPORT jdoubleArray JNICALL
|
NS_EXPORT jdoubleArray JNICALL
|
||||||
Java_org_mozilla_gecko_util_NativeJSObject_optDoubleArray(
|
Java_org_mozilla_gecko_util_NativeJSObject_optDoubleArray(
|
||||||
JNIEnv* env, jobject instance, jstring name, jdoubleArray fallback)
|
JNIEnv* env, jobject instance, jstring name, jdoubleArray fallback)
|
||||||
{
|
{
|
||||||
return nullptr; // TODO add implementation
|
return GetProperty<DoubleArrayProperty>(env, instance, name, FallbackOption::RETURN, fallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_EXPORT jint JNICALL
|
NS_EXPORT jint JNICALL
|
||||||
@ -708,14 +819,14 @@ NS_EXPORT jintArray JNICALL
|
|||||||
Java_org_mozilla_gecko_util_NativeJSObject_getIntArray(
|
Java_org_mozilla_gecko_util_NativeJSObject_getIntArray(
|
||||||
JNIEnv* env, jobject instance, jstring name)
|
JNIEnv* env, jobject instance, jstring name)
|
||||||
{
|
{
|
||||||
return nullptr; // TODO add implementation
|
return GetProperty<IntArrayProperty>(env, instance, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_EXPORT jintArray JNICALL
|
NS_EXPORT jintArray JNICALL
|
||||||
Java_org_mozilla_gecko_util_NativeJSObject_optIntArray(
|
Java_org_mozilla_gecko_util_NativeJSObject_optIntArray(
|
||||||
JNIEnv* env, jobject instance, jstring name, jintArray fallback)
|
JNIEnv* env, jobject instance, jstring name, jintArray fallback)
|
||||||
{
|
{
|
||||||
return nullptr; // TODO add implementation
|
return GetProperty<IntArrayProperty>(env, instance, name, FallbackOption::RETURN, fallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_EXPORT jobject JNICALL
|
NS_EXPORT jobject JNICALL
|
||||||
|
Loading…
Reference in New Issue
Block a user