// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/android/java/gin_java_script_to_java_types_coercion.h"
#include <stdint.h>
#include <unistd.h>
#include <cmath>
#include <limits>
#include <memory>
#include <string>
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/check_op.h"
#include "base/notreached.h"
#include "base/numerics/safe_conversions.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;
using base::android::ScopedJavaLocalRef;
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 ? std::floor(x) : std::ceil(x);
}
// Rounds to jlong using Java's type conversion rules.
jlong RoundDoubleToLong(const double& x) {
double intermediate = RoundDoubleTowardsZero(x);
// The int64_t 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_t kLimit = (INT64_C(1) << 63) - static_cast<uint64_t>(1 << 10);
DCHECK(kLimit > 0);
const double kLargestDoubleLessThanInt64Max = kLimit;
const double kSmallestDoubleGreaterThanInt64Min = -kLimit;
if (intermediate > kLargestDoubleLessThanInt64Max) {
return std::numeric_limits<int64_t>::max();
}
if (intermediate < kSmallestDoubleGreaterThanInt64Min) {
return std::numeric_limits<int64_t>::min();
}
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_t limits cast exactly to double values.
intermediate = std::min(
intermediate, static_cast<double>(std::numeric_limits<int32_t>::max()));
intermediate = std::max(
intermediate, static_cast<double>(std::numeric_limits<int32_t>::min()));
return static_cast<jint>(intermediate);
}
jvalue CoerceJavaScriptIntegerToJavaValue(JNIEnv* env,
int64_t integer_value,
const JavaType& target_type,
bool coerce_to_string,
mojom::GinJavaBridgeError* error) {
// 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;
switch (target_type.type) {
case JavaType::TypeByte:
result.b = static_cast<jbyte>(integer_value);
break;
case JavaType::TypeChar:
result.c = static_cast<jchar>(integer_value);
break;
case JavaType::TypeShort:
result.s = static_cast<jshort>(integer_value);
break;
case JavaType::TypeInt:
result.i = static_cast<jint>(integer_value);
break;
case JavaType::TypeLong:
result.j = integer_value;
break;
case JavaType::TypeFloat:
result.f = integer_value;
break;
case JavaType::TypeDouble:
result.d = integer_value;
break;
case JavaType::TypeObject:
// LIVECONNECT_COMPLIANCE: Existing behavior is to convert to null. Spec
// requires handling object equivalents of primitive types.
result.l = nullptr;
break;
case JavaType::TypeString:
result.l = coerce_to_string
? ConvertUTF8ToJavaString(
env, base::NumberToString(integer_value))
.Release()
: nullptr;
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 = nullptr;
break;
case JavaType::TypeVoid:
// Conversion to void must never happen.
NOTREACHED_IN_MIGRATION();
break;
}
return result;
}
jvalue CoerceJavaScriptDoubleToJavaValue(JNIEnv* env,
double double_value,
const JavaType& target_type,
bool coerce_to_string,
mojom::GinJavaBridgeError* error) {
// 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 = nullptr;
break;
case JavaType::TypeString:
result.l = coerce_to_string
? ConvertUTF8ToJavaString(
env, base::StringPrintf("%.6lg", double_value))
.Release()
: nullptr;
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 = nullptr;
break;
case JavaType::TypeVoid:
// Conversion to void must never happen.
NOTREACHED_IN_MIGRATION();
break;
}
return result;
}
jvalue CoerceJavaScriptBooleanToJavaValue(JNIEnv* env,
const base::Value& value,
const JavaType& target_type,
bool coerce_to_string,
mojom::GinJavaBridgeError* error) {
// See http://jdk6.java.net/plugin2/liveconnect/#JS_BOOLEAN_VALUES.
bool boolean_value = value.GetBool();
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 = nullptr;
break;
case JavaType::TypeString:
result.l = coerce_to_string ? ConvertUTF8ToJavaString(
env, boolean_value ? "true" : "false")
.Release()
: nullptr;
break;
// LIVECONNECT_COMPLIANCE: Existing behavior is to convert to 0. Spec
// requires converting to 0 or 1.
case JavaType::TypeByte:
result.b = 0;
break;
case JavaType::TypeChar:
result.c = 0;
break;
case JavaType::TypeShort:
result.s = 0;
break;
case JavaType::TypeInt:
result.i = 0;
break;
case JavaType::TypeLong:
result.j = 0;
break;
case JavaType::TypeFloat:
result.f = 0;
break;
case JavaType::TypeDouble:
result.d = 0;
break;
case JavaType::TypeArray:
// LIVECONNECT_COMPLIANCE: Existing behavior is to convert to null. Spec
// requires raising a JavaScript exception.
result.l = nullptr;
break;
case JavaType::TypeVoid:
// Conversion to void must never happen.
NOTREACHED_IN_MIGRATION();
break;
}
return result;
}
jvalue CoerceJavaScriptStringToJavaValue(JNIEnv* env,
const base::Value& value,
const JavaType& target_type,
mojom::GinJavaBridgeError* error) {
// See http://jdk6.java.net/plugin2/liveconnect/#JS_STRING_VALUES.
jvalue result;
switch (target_type.type) {
case JavaType::TypeString: {
result.l = ConvertUTF8ToJavaString(env, value.GetString()).Release();
break;
}
case JavaType::TypeObject:
// LIVECONNECT_COMPLIANCE: Existing behavior is to convert to null. Spec
// requires handling java.lang.Object.
result.l = nullptr;
break;
// LIVECONNECT_COMPLIANCE: Existing behavior is to convert to 0. Spec
// requires using valueOf() method of corresponding object type.
case JavaType::TypeByte:
result.b = 0;
break;
case JavaType::TypeShort:
result.s = 0;
break;
case JavaType::TypeInt:
result.i = 0;
break;
case JavaType::TypeLong:
result.j = 0;
break;
case JavaType::TypeFloat:
result.f = 0;
break;
case JavaType::TypeDouble:
result.d = 0;
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 = nullptr;
break;
case JavaType::TypeVoid:
// Conversion to void must never happen.
NOTREACHED_IN_MIGRATION();
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: {
ScopedJavaLocalRef<jclass> clazz(
base::android::GetClass(env, kJavaLangString));
return env->NewObjectArray(length, clazz.obj(), nullptr);
}
case JavaType::TypeVoid:
// Conversion to void must never happen.
case JavaType::TypeArray:
case JavaType::TypeObject:
// Not handled.
NOTREACHED_IN_MIGRATION();
}
return nullptr;
}
// 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_IN_MIGRATION();
}
base::android::CheckException(env);
}
jvalue CoerceJavaScriptNullOrUndefinedToJavaValue(
JNIEnv* env,
const base::Value& value,
const JavaType& target_type,
bool coerce_to_string,
mojom::GinJavaBridgeError* error) {
bool is_undefined = false;
std::unique_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 = nullptr;
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()
: nullptr;
break;
case JavaType::TypeByte:
result.b = 0;
break;
case JavaType::TypeChar:
result.c = 0;
break;
case JavaType::TypeShort:
result.s = 0;
break;
case JavaType::TypeInt:
result.i = 0;
break;
case JavaType::TypeLong:
result.j = 0;
break;
case JavaType::TypeFloat:
result.f = 0;
break;
case JavaType::TypeDouble:
result.d = 0;
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 = nullptr;
break;
case JavaType::TypeVoid:
// Conversion to void must never happen.
NOTREACHED_IN_MIGRATION();
break;
}
return result;
}
jobject CoerceJavaScriptListToArray(JNIEnv* env,
const base::Value::List& list,
const JavaType& target_type,
const ObjectRefs& object_refs,
mojom::GinJavaBridgeError* error) {
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 nullptr;
}
// LIVECONNECT_COMPLIANCE: Existing behavior is to return null for object
// arrays. Spec requires handling object arrays.
if (target_inner_type.type == JavaType::TypeObject) {
return nullptr;
}
// Coerce the length.
if (!base::IsValueInRangeForNumericType<jsize>(list.size())) {
return nullptr;
}
jsize length = static_cast<jsize>(list.size());
// Create the Java array.
jobject result = CreateJavaArray(env, target_inner_type, length);
if (!result) {
return nullptr;
}
jsize i = 0;
for (const auto& value_element : list) {
jvalue element = CoerceJavaScriptValueToJavaValue(
env, value_element, target_inner_type, false, object_refs, error);
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::Dict& dict,
const JavaType& target_type,
const ObjectRefs& object_refs,
mojom::GinJavaBridgeError* error) {
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 nullptr;
}
// LIVECONNECT_COMPLIANCE: Existing behavior is to return null for object
// arrays. Spec requires handling object arrays.
if (target_inner_type.type == JavaType::TypeObject) {
return nullptr;
}
// If the object does not have a length property, return null.
const base::Value* length_value = dict.Find("length");
if (!length_value) {
return nullptr;
}
// 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->is_int()) {
if (length_value->GetInt() >= 0 &&
length_value->GetInt() <= std::numeric_limits<int32_t>::max()) {
length = static_cast<jsize>(length_value->GetInt());
}
} else if (length_value->is_double()) {
double double_length = length_value->GetDouble();
if (double_length >= 0.0 &&
double_length <= std::numeric_limits<int32_t>::max()) {
length = static_cast<jsize>(double_length);
}
}
if (length == -1) {
return nullptr;
}
jobject result = CreateJavaArray(env, target_inner_type, length);
if (!result) {
return nullptr;
}
base::Value null_value;
for (jsize i = 0; i < length; ++i) {
const std::string key(base::NumberToString(i));
const base::Value* value_element = dict.Find(key);
if (!value_element)
value_element = &null_value;
jvalue element = CoerceJavaScriptValueToJavaValue(
env, *value_element, target_inner_type, false, object_refs, error);
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,
mojom::GinJavaBridgeError* error) {
// 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)) {
std::unique_ptr<const GinJavaBridgeValue> gin_value(
GinJavaBridgeValue::FromValue(&value));
DCHECK(gin_value);
DCHECK(gin_value->IsType(GinJavaBridgeValue::TYPE_OBJECT_ID));
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));
}
}
DCHECK(!target_type.class_ref.is_null());
DCHECK(!obj.is_null());
if (env->IsInstanceOf(obj.obj(), target_type.class_ref.obj()) ==
JNI_TRUE) {
result.l = obj.Release();
} else {
result.l = nullptr;
*error = mojom::GinJavaBridgeError::kGinJavaBridgeNonAssignableTypes;
}
} 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 = nullptr;
}
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()
: nullptr;
break;
// LIVECONNECT_COMPLIANCE: Existing behavior is to convert to 0. Spec
// requires raising a JavaScript exception.
case JavaType::TypeByte:
result.b = 0;
break;
case JavaType::TypeShort:
result.s = 0;
break;
case JavaType::TypeInt:
result.i = 0;
break;
case JavaType::TypeLong:
result.j = 0;
break;
case JavaType::TypeFloat:
result.f = 0;
break;
case JavaType::TypeDouble:
result.d = 0;
break;
case JavaType::TypeChar:
result.c = 0;
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.is_dict()) {
result.l = CoerceJavaScriptDictionaryToArray(
env, value.GetDict(), target_type, object_refs, error);
} else if (value.is_list()) {
result.l = CoerceJavaScriptListToArray(env, value.GetList(),
target_type, object_refs, error);
} else {
result.l = nullptr;
}
break;
case JavaType::TypeVoid:
// Conversion to void must never happen.
NOTREACHED_IN_MIGRATION();
break;
}
return result;
}
jvalue CoerceGinJavaBridgeValueToJavaValue(JNIEnv* env,
const base::Value& value,
const JavaType& target_type,
bool coerce_to_string,
const ObjectRefs& object_refs,
mojom::GinJavaBridgeError* error) {
DCHECK(GinJavaBridgeValue::ContainsGinJavaBridgeValue(&value));
std::unique_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, error);
case GinJavaBridgeValue::TYPE_NONFINITE: {
float float_value = 0.f;
if (!gin_value->GetAsNonFinite(&float_value))
return jvalue();
return CoerceJavaScriptDoubleToJavaValue(
env, float_value, target_type, coerce_to_string, error);
}
case GinJavaBridgeValue::TYPE_OBJECT_ID:
return CoerceJavaScriptObjectToJavaValue(
env, value, target_type, coerce_to_string, object_refs, error);
case GinJavaBridgeValue::TYPE_UINT32: {
uint32_t uint32_value = 0;
if (!gin_value->GetAsUInt32(&uint32_value))
return jvalue();
return CoerceJavaScriptIntegerToJavaValue(env, uint32_value, target_type,
coerce_to_string, error);
}
default:
NOTREACHED_IN_MIGRATION();
}
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 = nullptr;
}
}
jvalue CoerceJavaScriptValueToJavaValue(JNIEnv* env,
const base::Value& value,
const JavaType& target_type,
bool coerce_to_string,
const ObjectRefs& object_refs,
mojom::GinJavaBridgeError* error) {
// 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.type()) {
case base::Value::Type::INTEGER:
return CoerceJavaScriptIntegerToJavaValue(
env, value.GetInt(), target_type, coerce_to_string, error);
case base::Value::Type::DOUBLE: {
return CoerceJavaScriptDoubleToJavaValue(
env, value.GetDouble(), target_type, coerce_to_string, error);
}
case base::Value::Type::BOOLEAN:
return CoerceJavaScriptBooleanToJavaValue(
env, value, target_type, coerce_to_string, error);
case base::Value::Type::STRING:
return CoerceJavaScriptStringToJavaValue(env, value, target_type, error);
case base::Value::Type::DICT:
case base::Value::Type::LIST:
return CoerceJavaScriptObjectToJavaValue(
env, value, target_type, coerce_to_string, object_refs, error);
case base::Value::Type::NONE:
return CoerceJavaScriptNullOrUndefinedToJavaValue(
env, value, target_type, coerce_to_string, error);
case base::Value::Type::BINARY:
return CoerceGinJavaBridgeValueToJavaValue(
env, value, target_type, coerce_to_string, object_refs, error);
}
NOTREACHED_IN_MIGRATION();
return jvalue();
}
} // namespace content