summaryrefslogtreecommitdiffstats
path: root/chromium/content/browser/renderer_host/java/gin_java_script_to_java_types_coercion.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/content/browser/renderer_host/java/gin_java_script_to_java_types_coercion.cc')
-rw-r--r--chromium/content/browser/renderer_host/java/gin_java_script_to_java_types_coercion.cc705
1 files changed, 705 insertions, 0 deletions
diff --git a/chromium/content/browser/renderer_host/java/gin_java_script_to_java_types_coercion.cc b/chromium/content/browser/renderer_host/java/gin_java_script_to_java_types_coercion.cc
new file mode 100644
index 00000000000..8f7c29f16eb
--- /dev/null
+++ b/chromium/content/browser/renderer_host/java/gin_java_script_to_java_types_coercion.cc
@@ -0,0 +1,705 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/renderer_host/java/gin_java_script_to_java_types_coercion.h"
+
+#include <unistd.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/common/android/gin_java_bridge_value.h"
+
+using base::android::ConvertUTF8ToJavaString;
+
+namespace content {
+
+namespace {
+
+const char kJavaLangString[] = "java/lang/String";
+const char kUndefined[] = "undefined";
+
+double RoundDoubleTowardsZero(const double& x) {
+ if (std::isnan(x)) {
+ return 0.0;
+ }
+ return x > 0.0 ? floor(x) : ceil(x);
+}
+
+// Rounds to jlong using Java's type conversion rules.
+jlong RoundDoubleToLong(const double& x) {
+ double intermediate = RoundDoubleTowardsZero(x);
+ // The int64 limits can not be converted exactly to double values, so we
+ // compare to custom constants. kint64max is 2^63 - 1, but the spacing
+ // between double values in the the range 2^62 to 2^63 is 2^10. The cast is
+ // required to silence a spurious gcc warning for integer overflow.
+ const int64 kLimit = (GG_INT64_C(1) << 63) - static_cast<uint64>(1 << 10);
+ DCHECK(kLimit > 0);
+ const double kLargestDoubleLessThanInt64Max = kLimit;
+ const double kSmallestDoubleGreaterThanInt64Min = -kLimit;
+ if (intermediate > kLargestDoubleLessThanInt64Max) {
+ return kint64max;
+ }
+ if (intermediate < kSmallestDoubleGreaterThanInt64Min) {
+ return kint64min;
+ }
+ return static_cast<jlong>(intermediate);
+}
+
+// Rounds to jint using Java's type conversion rules.
+jint RoundDoubleToInt(const double& x) {
+ double intermediate = RoundDoubleTowardsZero(x);
+ // The int32 limits cast exactly to double values.
+ intermediate = std::min(intermediate, static_cast<double>(kint32max));
+ intermediate = std::max(intermediate, static_cast<double>(kint32min));
+ return static_cast<jint>(intermediate);
+}
+
+jvalue CoerceJavaScriptIntegerToJavaValue(JNIEnv* env,
+ const base::Value* value,
+ const JavaType& target_type,
+ bool coerce_to_string) {
+ // See http://jdk6.java.net/plugin2/liveconnect/#JS_NUMBER_VALUES.
+
+ // For conversion to numeric types, we need to replicate Java's type
+ // conversion rules. This requires that for integer values, we simply discard
+ // all but the lowest n buts, where n is the number of bits in the target
+ // type.
+ jvalue result;
+ int int_value;
+ value->GetAsInteger(&int_value);
+ switch (target_type.type) {
+ case JavaType::TypeByte:
+ result.b = static_cast<jbyte>(int_value);
+ break;
+ case JavaType::TypeChar:
+ result.c = static_cast<jchar>(int_value);
+ break;
+ case JavaType::TypeShort:
+ result.s = static_cast<jshort>(int_value);
+ break;
+ case JavaType::TypeInt:
+ result.i = int_value;
+ break;
+ case JavaType::TypeLong:
+ result.j = int_value;
+ break;
+ case JavaType::TypeFloat:
+ result.f = int_value;
+ break;
+ case JavaType::TypeDouble:
+ result.d = int_value;
+ break;
+ case JavaType::TypeObject:
+ // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to null. Spec
+ // requires handling object equivalents of primitive types.
+ result.l = NULL;
+ break;
+ case JavaType::TypeString:
+ result.l = coerce_to_string
+ ? ConvertUTF8ToJavaString(
+ env, base::Int64ToString(int_value)).Release()
+ : NULL;
+ break;
+ case JavaType::TypeBoolean:
+ // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to false. Spec
+ // requires converting to false for 0 or NaN, true otherwise.
+ result.z = JNI_FALSE;
+ break;
+ case JavaType::TypeArray:
+ // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to null. Spec
+ // requires raising a JavaScript exception.
+ result.l = NULL;
+ break;
+ case JavaType::TypeVoid:
+ // Conversion to void must never happen.
+ NOTREACHED();
+ break;
+ }
+ return result;
+}
+
+jvalue CoerceJavaScriptDoubleToJavaValue(JNIEnv* env,
+ double double_value,
+ const JavaType& target_type,
+ bool coerce_to_string) {
+ // See http://jdk6.java.net/plugin2/liveconnect/#JS_NUMBER_VALUES.
+ // For conversion to numeric types, we need to replicate Java's type
+ // conversion rules.
+ jvalue result;
+ switch (target_type.type) {
+ case JavaType::TypeByte:
+ result.b = static_cast<jbyte>(RoundDoubleToInt(double_value));
+ break;
+ case JavaType::TypeChar:
+ // LIVECONNECT_COMPLIANCE: Existing behavior is to convert double to 0.
+ // Spec requires converting doubles similarly to how we convert doubles to
+ // other numeric types.
+ result.c = 0;
+ break;
+ case JavaType::TypeShort:
+ result.s = static_cast<jshort>(RoundDoubleToInt(double_value));
+ break;
+ case JavaType::TypeInt:
+ result.i = RoundDoubleToInt(double_value);
+ break;
+ case JavaType::TypeLong:
+ result.j = RoundDoubleToLong(double_value);
+ break;
+ case JavaType::TypeFloat:
+ result.f = static_cast<jfloat>(double_value);
+ break;
+ case JavaType::TypeDouble:
+ result.d = double_value;
+ break;
+ case JavaType::TypeObject:
+ // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to null. Spec
+ // requires handling object equivalents of primitive types.
+ result.l = NULL;
+ break;
+ case JavaType::TypeString:
+ result.l =
+ coerce_to_string
+ ? ConvertUTF8ToJavaString(
+ env, base::StringPrintf("%.6lg", double_value)).Release()
+ : NULL;
+ break;
+ case JavaType::TypeBoolean:
+ // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to false. Spec
+ // requires converting to false for 0 or NaN, true otherwise.
+ result.z = JNI_FALSE;
+ break;
+ case JavaType::TypeArray:
+ // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to null. Spec
+ // requires raising a JavaScript exception.
+ result.l = NULL;
+ break;
+ case JavaType::TypeVoid:
+ // Conversion to void must never happen.
+ NOTREACHED();
+ break;
+ }
+ return result;
+}
+
+jvalue CoerceJavaScriptBooleanToJavaValue(JNIEnv* env,
+ const base::Value* value,
+ const JavaType& target_type,
+ bool coerce_to_string) {
+ // See http://jdk6.java.net/plugin2/liveconnect/#JS_BOOLEAN_VALUES.
+ bool boolean_value;
+ value->GetAsBoolean(&boolean_value);
+ jvalue result;
+ switch (target_type.type) {
+ case JavaType::TypeBoolean:
+ result.z = boolean_value ? JNI_TRUE : JNI_FALSE;
+ break;
+ case JavaType::TypeObject:
+ // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec
+ // requires handling java.lang.Boolean and java.lang.Object.
+ result.l = NULL;
+ break;
+ case JavaType::TypeString:
+ result.l = coerce_to_string
+ ? ConvertUTF8ToJavaString(
+ env, boolean_value ? "true" : "false").Release()
+ : NULL;
+ break;
+ case JavaType::TypeByte:
+ case JavaType::TypeChar:
+ case JavaType::TypeShort:
+ case JavaType::TypeInt:
+ case JavaType::TypeLong:
+ case JavaType::TypeFloat:
+ case JavaType::TypeDouble: {
+ // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to 0. Spec
+ // requires converting to 0 or 1.
+ jvalue null_value = {0};
+ result = null_value;
+ break;
+ }
+ case JavaType::TypeArray:
+ // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec
+ // requires raising a JavaScript exception.
+ result.l = NULL;
+ break;
+ case JavaType::TypeVoid:
+ // Conversion to void must never happen.
+ NOTREACHED();
+ break;
+ }
+ return result;
+}
+
+jvalue CoerceJavaScriptStringToJavaValue(JNIEnv* env,
+ const base::Value* value,
+ const JavaType& target_type) {
+ // See http://jdk6.java.net/plugin2/liveconnect/#JS_STRING_VALUES.
+ jvalue result;
+ switch (target_type.type) {
+ case JavaType::TypeString: {
+ std::string string_result;
+ value->GetAsString(&string_result);
+ result.l = ConvertUTF8ToJavaString(env, string_result).Release();
+ break;
+ }
+ case JavaType::TypeObject:
+ // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec
+ // requires handling java.lang.Object.
+ result.l = NULL;
+ break;
+ case JavaType::TypeByte:
+ case JavaType::TypeShort:
+ case JavaType::TypeInt:
+ case JavaType::TypeLong:
+ case JavaType::TypeFloat:
+ case JavaType::TypeDouble: {
+ // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to 0. Spec
+ // requires using valueOf() method of corresponding object type.
+ jvalue null_value = {0};
+ result = null_value;
+ break;
+ }
+ case JavaType::TypeChar:
+ // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to 0. Spec
+ // requires using java.lang.Short.decode().
+ result.c = 0;
+ break;
+ case JavaType::TypeBoolean:
+ // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to false. Spec
+ // requires converting the empty string to false, otherwise true.
+ result.z = JNI_FALSE;
+ break;
+ case JavaType::TypeArray:
+ // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec
+ // requires raising a JavaScript exception.
+ result.l = NULL;
+ break;
+ case JavaType::TypeVoid:
+ // Conversion to void must never happen.
+ NOTREACHED();
+ break;
+ }
+ return result;
+}
+
+// Note that this only handles primitive types and strings.
+jobject CreateJavaArray(JNIEnv* env, const JavaType& type, jsize length) {
+ switch (type.type) {
+ case JavaType::TypeBoolean:
+ return env->NewBooleanArray(length);
+ case JavaType::TypeByte:
+ return env->NewByteArray(length);
+ case JavaType::TypeChar:
+ return env->NewCharArray(length);
+ case JavaType::TypeShort:
+ return env->NewShortArray(length);
+ case JavaType::TypeInt:
+ return env->NewIntArray(length);
+ case JavaType::TypeLong:
+ return env->NewLongArray(length);
+ case JavaType::TypeFloat:
+ return env->NewFloatArray(length);
+ case JavaType::TypeDouble:
+ return env->NewDoubleArray(length);
+ case JavaType::TypeString: {
+ base::android::ScopedJavaLocalRef<jclass> clazz(
+ base::android::GetClass(env, kJavaLangString));
+ return env->NewObjectArray(length, clazz.obj(), NULL);
+ }
+ case JavaType::TypeVoid:
+ // Conversion to void must never happen.
+ case JavaType::TypeArray:
+ case JavaType::TypeObject:
+ // Not handled.
+ NOTREACHED();
+ }
+ return NULL;
+}
+
+// Sets the specified element of the supplied array to the value of the
+// supplied jvalue. Requires that the type of the array matches that of the
+// jvalue. Handles only primitive types and strings. Note that in the case of a
+// string, the array takes a new reference to the string object.
+void SetArrayElement(JNIEnv* env,
+ jobject array,
+ const JavaType& type,
+ jsize index,
+ const jvalue& value) {
+ switch (type.type) {
+ case JavaType::TypeBoolean:
+ env->SetBooleanArrayRegion(static_cast<jbooleanArray>(array), index, 1,
+ &value.z);
+ break;
+ case JavaType::TypeByte:
+ env->SetByteArrayRegion(static_cast<jbyteArray>(array), index, 1,
+ &value.b);
+ break;
+ case JavaType::TypeChar:
+ env->SetCharArrayRegion(static_cast<jcharArray>(array), index, 1,
+ &value.c);
+ break;
+ case JavaType::TypeShort:
+ env->SetShortArrayRegion(static_cast<jshortArray>(array), index, 1,
+ &value.s);
+ break;
+ case JavaType::TypeInt:
+ env->SetIntArrayRegion(static_cast<jintArray>(array), index, 1,
+ &value.i);
+ break;
+ case JavaType::TypeLong:
+ env->SetLongArrayRegion(static_cast<jlongArray>(array), index, 1,
+ &value.j);
+ break;
+ case JavaType::TypeFloat:
+ env->SetFloatArrayRegion(static_cast<jfloatArray>(array), index, 1,
+ &value.f);
+ break;
+ case JavaType::TypeDouble:
+ env->SetDoubleArrayRegion(static_cast<jdoubleArray>(array), index, 1,
+ &value.d);
+ break;
+ case JavaType::TypeString:
+ env->SetObjectArrayElement(static_cast<jobjectArray>(array), index,
+ value.l);
+ break;
+ case JavaType::TypeVoid:
+ // Conversion to void must never happen.
+ case JavaType::TypeArray:
+ case JavaType::TypeObject:
+ // Not handled.
+ NOTREACHED();
+ }
+ base::android::CheckException(env);
+}
+
+jvalue CoerceJavaScriptNullOrUndefinedToJavaValue(JNIEnv* env,
+ const base::Value* value,
+ const JavaType& target_type,
+ bool coerce_to_string) {
+ bool is_undefined = false;
+ scoped_ptr<const GinJavaBridgeValue> gin_value;
+ if (GinJavaBridgeValue::ContainsGinJavaBridgeValue(value)) {
+ gin_value = GinJavaBridgeValue::FromValue(value);
+ if (gin_value->IsType(GinJavaBridgeValue::TYPE_UNDEFINED)) {
+ is_undefined = true;
+ }
+ }
+ jvalue result;
+ switch (target_type.type) {
+ case JavaType::TypeObject:
+ result.l = NULL;
+ break;
+ case JavaType::TypeString:
+ // LIVECONNECT_COMPLIANCE: Existing behavior is to convert undefined to
+ // "undefined". Spec requires converting undefined to NULL.
+ result.l = (coerce_to_string && is_undefined)
+ ? ConvertUTF8ToJavaString(env, kUndefined).Release()
+ : NULL;
+ break;
+ case JavaType::TypeByte:
+ case JavaType::TypeChar:
+ case JavaType::TypeShort:
+ case JavaType::TypeInt:
+ case JavaType::TypeLong:
+ case JavaType::TypeFloat:
+ case JavaType::TypeDouble: {
+ jvalue null_value = {0};
+ result = null_value;
+ break;
+ }
+ case JavaType::TypeBoolean:
+ result.z = JNI_FALSE;
+ break;
+ case JavaType::TypeArray:
+ // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec
+ // requires raising a JavaScript exception.
+ result.l = NULL;
+ break;
+ case JavaType::TypeVoid:
+ // Conversion to void must never happen.
+ NOTREACHED();
+ break;
+ }
+ return result;
+}
+
+jobject CoerceJavaScriptListToArray(JNIEnv* env,
+ const base::Value* value,
+ const JavaType& target_type,
+ const ObjectRefs& object_refs) {
+ DCHECK_EQ(JavaType::TypeArray, target_type.type);
+ const JavaType& target_inner_type = *target_type.inner_type.get();
+ // LIVECONNECT_COMPLIANCE: Existing behavior is to return null for
+ // multi-dimensional arrays. Spec requires handling multi-demensional arrays.
+ if (target_inner_type.type == JavaType::TypeArray) {
+ return NULL;
+ }
+
+ // LIVECONNECT_COMPLIANCE: Existing behavior is to return null for object
+ // arrays. Spec requires handling object arrays.
+ if (target_inner_type.type == JavaType::TypeObject) {
+ return NULL;
+ }
+
+ const base::ListValue* list_value;
+ value->GetAsList(&list_value);
+ // Create the Java array.
+ jsize length = static_cast<jsize>(list_value->GetSize());
+ jobject result = CreateJavaArray(env, target_inner_type, length);
+ if (!result) {
+ return NULL;
+ }
+ scoped_ptr<base::Value> null_value(base::Value::CreateNullValue());
+ for (jsize i = 0; i < length; ++i) {
+ const base::Value* value_element = null_value.get();
+ list_value->Get(i, &value_element);
+ jvalue element = CoerceJavaScriptValueToJavaValue(
+ env, value_element, target_inner_type, false, object_refs);
+ SetArrayElement(env, result, target_inner_type, i, element);
+ // CoerceJavaScriptValueToJavaValue() creates new local references to
+ // strings, objects and arrays. Of these, only strings can occur here.
+ // SetArrayElement() causes the array to take its own reference to the
+ // string, so we can now release the local reference.
+ DCHECK_NE(JavaType::TypeObject, target_inner_type.type);
+ DCHECK_NE(JavaType::TypeArray, target_inner_type.type);
+ ReleaseJavaValueIfRequired(env, &element, target_inner_type);
+ }
+
+ return result;
+}
+
+jobject CoerceJavaScriptDictionaryToArray(JNIEnv* env,
+ const base::Value* value,
+ const JavaType& target_type,
+ const ObjectRefs& object_refs) {
+ DCHECK_EQ(JavaType::TypeArray, target_type.type);
+
+ const JavaType& target_inner_type = *target_type.inner_type.get();
+ // LIVECONNECT_COMPLIANCE: Existing behavior is to return null for
+ // multi-dimensional arrays. Spec requires handling multi-demensional arrays.
+ if (target_inner_type.type == JavaType::TypeArray) {
+ return NULL;
+ }
+
+ // LIVECONNECT_COMPLIANCE: Existing behavior is to return null for object
+ // arrays. Spec requires handling object arrays.
+ if (target_inner_type.type == JavaType::TypeObject) {
+ return NULL;
+ }
+
+ const base::DictionaryValue* dictionary_value;
+ value->GetAsDictionary(&dictionary_value);
+ const base::Value* length_value;
+ // If the object does not have a length property, return null.
+ if (!dictionary_value->Get("length", &length_value)) {
+ return NULL;
+ }
+
+ // If the length property does not have numeric type, or is outside the valid
+ // range for a Java array length, return null.
+ jsize length = -1;
+ if (length_value->IsType(base::Value::TYPE_INTEGER)) {
+ int int_length;
+ length_value->GetAsInteger(&int_length);
+ if (int_length >= 0 && int_length <= kint32max) {
+ length = static_cast<jsize>(int_length);
+ }
+ } else if (length_value->IsType(base::Value::TYPE_DOUBLE)) {
+ double double_length;
+ length_value->GetAsDouble(&double_length);
+ if (double_length >= 0.0 && double_length <= kint32max) {
+ length = static_cast<jsize>(double_length);
+ }
+ }
+ if (length == -1) {
+ return NULL;
+ }
+
+ jobject result = CreateJavaArray(env, target_inner_type, length);
+ if (!result) {
+ return NULL;
+ }
+ scoped_ptr<base::Value> null_value(base::Value::CreateNullValue());
+ for (jsize i = 0; i < length; ++i) {
+ const std::string key(base::IntToString(i));
+ const base::Value* value_element = null_value.get();
+ if (dictionary_value->HasKey(key)) {
+ dictionary_value->Get(key, &value_element);
+ }
+ jvalue element = CoerceJavaScriptValueToJavaValue(
+ env, value_element, target_inner_type, false, object_refs);
+ SetArrayElement(env, result, target_inner_type, i, element);
+ // CoerceJavaScriptValueToJavaValue() creates new local references to
+ // strings, objects and arrays. Of these, only strings can occur here.
+ // SetArrayElement() causes the array to take its own reference to the
+ // string, so we can now release the local reference.
+ DCHECK_NE(JavaType::TypeObject, target_inner_type.type);
+ DCHECK_NE(JavaType::TypeArray, target_inner_type.type);
+ ReleaseJavaValueIfRequired(env, &element, target_inner_type);
+ }
+
+ return result;
+}
+
+jvalue CoerceJavaScriptObjectToJavaValue(JNIEnv* env,
+ const base::Value* value,
+ const JavaType& target_type,
+ bool coerce_to_string,
+ const ObjectRefs& object_refs) {
+ // This covers both JavaScript objects (including arrays) and Java objects.
+ // See http://jdk6.java.net/plugin2/liveconnect/#JS_OTHER_OBJECTS,
+ // http://jdk6.java.net/plugin2/liveconnect/#JS_ARRAY_VALUES and
+ // http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_OBJECTS
+ jvalue result;
+ switch (target_type.type) {
+ case JavaType::TypeObject: {
+ if (GinJavaBridgeValue::ContainsGinJavaBridgeValue(value)) {
+ scoped_ptr<const GinJavaBridgeValue> gin_value(
+ GinJavaBridgeValue::FromValue(value));
+ DCHECK(gin_value);
+ DCHECK(gin_value->IsType(GinJavaBridgeValue::TYPE_OBJECT_ID));
+ base::android::ScopedJavaLocalRef<jobject> obj;
+ GinJavaBoundObject::ObjectID object_id;
+ if (gin_value->GetAsObjectID(&object_id)) {
+ ObjectRefs::const_iterator iter = object_refs.find(object_id);
+ if (iter != object_refs.end()) {
+ obj.Reset(iter->second.get(env));
+ }
+ }
+ result.l = obj.Release();
+ } else {
+ // LIVECONNECT_COMPLIANCE: Existing behavior is to pass null. Spec
+ // requires converting if the target type is
+ // netscape.javascript.JSObject, otherwise raising a JavaScript
+ // exception.
+ result.l = NULL;
+ }
+ break;
+ }
+ case JavaType::TypeString:
+ // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to
+ // "undefined". Spec requires calling toString() on the Java object.
+ result.l = coerce_to_string
+ ? ConvertUTF8ToJavaString(env, kUndefined).Release()
+ : NULL;
+ break;
+ case JavaType::TypeByte:
+ case JavaType::TypeShort:
+ case JavaType::TypeInt:
+ case JavaType::TypeLong:
+ case JavaType::TypeFloat:
+ case JavaType::TypeDouble:
+ case JavaType::TypeChar: {
+ // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to 0. Spec
+ // requires raising a JavaScript exception.
+ jvalue null_value = {0};
+ result = null_value;
+ break;
+ }
+ case JavaType::TypeBoolean:
+ // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to false. Spec
+ // requires raising a JavaScript exception.
+ result.z = JNI_FALSE;
+ break;
+ case JavaType::TypeArray:
+ if (value->IsType(base::Value::TYPE_DICTIONARY)) {
+ result.l = CoerceJavaScriptDictionaryToArray(
+ env, value, target_type, object_refs);
+ } else if (value->IsType(base::Value::TYPE_LIST)) {
+ result.l =
+ CoerceJavaScriptListToArray(env, value, target_type, object_refs);
+ } else {
+ result.l = NULL;
+ }
+ break;
+ case JavaType::TypeVoid:
+ // Conversion to void must never happen.
+ NOTREACHED();
+ break;
+ }
+ return result;
+}
+
+jvalue CoerceGinJavaBridgeValueToJavaValue(JNIEnv* env,
+ const base::Value* value,
+ const JavaType& target_type,
+ bool coerce_to_string,
+ const ObjectRefs& object_refs) {
+ DCHECK(GinJavaBridgeValue::ContainsGinJavaBridgeValue(value));
+ scoped_ptr<const GinJavaBridgeValue> gin_value(
+ GinJavaBridgeValue::FromValue(value));
+ switch (gin_value->GetType()) {
+ case GinJavaBridgeValue::TYPE_UNDEFINED:
+ return CoerceJavaScriptNullOrUndefinedToJavaValue(
+ env, value, target_type, coerce_to_string);
+ case GinJavaBridgeValue::TYPE_NONFINITE: {
+ float float_value;
+ gin_value->GetAsNonFinite(&float_value);
+ return CoerceJavaScriptDoubleToJavaValue(
+ env, float_value, target_type, coerce_to_string);
+ }
+ case GinJavaBridgeValue::TYPE_OBJECT_ID:
+ return CoerceJavaScriptObjectToJavaValue(
+ env, value, target_type, coerce_to_string, object_refs);
+ default:
+ NOTREACHED();
+ }
+ return jvalue();
+}
+
+} // namespace
+
+
+void ReleaseJavaValueIfRequired(JNIEnv* env,
+ jvalue* value,
+ const JavaType& type) {
+ if (type.type == JavaType::TypeString || type.type == JavaType::TypeObject ||
+ type.type == JavaType::TypeArray) {
+ env->DeleteLocalRef(value->l);
+ value->l = NULL;
+ }
+}
+
+jvalue CoerceJavaScriptValueToJavaValue(JNIEnv* env,
+ const base::Value* value,
+ const JavaType& target_type,
+ bool coerce_to_string,
+ const ObjectRefs& object_refs) {
+ // Note that in all these conversions, the relevant field of the jvalue must
+ // always be explicitly set, as jvalue does not initialize its fields.
+
+ switch (value->GetType()) {
+ case base::Value::TYPE_INTEGER:
+ return CoerceJavaScriptIntegerToJavaValue(
+ env, value, target_type, coerce_to_string);
+ case base::Value::TYPE_DOUBLE: {
+ double double_value;
+ value->GetAsDouble(&double_value);
+ return CoerceJavaScriptDoubleToJavaValue(
+ env, double_value, target_type, coerce_to_string);
+ }
+ case base::Value::TYPE_BOOLEAN:
+ return CoerceJavaScriptBooleanToJavaValue(
+ env, value, target_type, coerce_to_string);
+ case base::Value::TYPE_STRING:
+ return CoerceJavaScriptStringToJavaValue(env, value, target_type);
+ case base::Value::TYPE_DICTIONARY:
+ case base::Value::TYPE_LIST:
+ return CoerceJavaScriptObjectToJavaValue(
+ env, value, target_type, coerce_to_string, object_refs);
+ case base::Value::TYPE_NULL:
+ return CoerceJavaScriptNullOrUndefinedToJavaValue(
+ env, value, target_type, coerce_to_string);
+ case base::Value::TYPE_BINARY:
+ return CoerceGinJavaBridgeValueToJavaValue(
+ env, value, target_type, coerce_to_string, object_refs);
+ }
+ NOTREACHED();
+ return jvalue();
+}
+
+} // namespace content