Index: content/browser/android/java/gin_java_script_to_java_types_coercion.cc |
diff --git a/content/browser/android/java/gin_java_script_to_java_types_coercion.cc b/content/browser/android/java/gin_java_script_to_java_types_coercion.cc |
index 75f902f3b26703480d551437517bd4537865a484..3d6bee9d51b3a2e80b5185bf917c9240d3aa1575 100644 |
--- a/content/browser/android/java/gin_java_script_to_java_types_coercion.cc |
+++ b/content/browser/android/java/gin_java_script_to_java_types_coercion.cc |
@@ -14,6 +14,8 @@ |
#include "content/common/android/gin_java_bridge_value.h" |
#include "third_party/WebKit/public/platform/WebString.h" |
+using base::android::ScopedJavaLocalRef; |
+ |
namespace content { |
namespace { |
@@ -67,7 +69,8 @@ jint RoundDoubleToInt(const double& x) { |
jvalue CoerceJavaScriptIntegerToJavaValue(JNIEnv* env, |
const base::Value* value, |
const JavaType& target_type, |
- bool coerce_to_string) { |
+ bool coerce_to_string, |
+ GinJavaBridgeError* error) { |
// See http://jdk6.java.net/plugin2/liveconnect/#JS_NUMBER_VALUES. |
// For conversion to numeric types, we need to replicate Java's type |
@@ -130,7 +133,8 @@ jvalue CoerceJavaScriptIntegerToJavaValue(JNIEnv* env, |
jvalue CoerceJavaScriptDoubleToJavaValue(JNIEnv* env, |
double double_value, |
const JavaType& target_type, |
- bool coerce_to_string) { |
+ bool coerce_to_string, |
+ 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. |
@@ -192,7 +196,8 @@ jvalue CoerceJavaScriptDoubleToJavaValue(JNIEnv* env, |
jvalue CoerceJavaScriptBooleanToJavaValue(JNIEnv* env, |
const base::Value* value, |
const JavaType& target_type, |
- bool coerce_to_string) { |
+ bool coerce_to_string, |
+ GinJavaBridgeError* error) { |
// See http://jdk6.java.net/plugin2/liveconnect/#JS_BOOLEAN_VALUES. |
bool boolean_value; |
value->GetAsBoolean(&boolean_value); |
@@ -239,7 +244,8 @@ jvalue CoerceJavaScriptBooleanToJavaValue(JNIEnv* env, |
jvalue CoerceJavaScriptStringToJavaValue(JNIEnv* env, |
const base::Value* value, |
- const JavaType& target_type) { |
+ const JavaType& target_type, |
+ GinJavaBridgeError* error) { |
// See http://jdk6.java.net/plugin2/liveconnect/#JS_STRING_VALUES. |
jvalue result; |
switch (target_type.type) { |
@@ -309,7 +315,7 @@ jobject CreateJavaArray(JNIEnv* env, const JavaType& type, jsize length) { |
case JavaType::TypeDouble: |
return env->NewDoubleArray(length); |
case JavaType::TypeString: { |
- base::android::ScopedJavaLocalRef<jclass> clazz( |
+ ScopedJavaLocalRef<jclass> clazz( |
base::android::GetClass(env, kJavaLangString)); |
return env->NewObjectArray(length, clazz.obj(), NULL); |
} |
@@ -382,7 +388,8 @@ void SetArrayElement(JNIEnv* env, |
jvalue CoerceJavaScriptNullOrUndefinedToJavaValue(JNIEnv* env, |
const base::Value* value, |
const JavaType& target_type, |
- bool coerce_to_string) { |
+ bool coerce_to_string, |
+ GinJavaBridgeError* error) { |
bool is_undefined = false; |
scoped_ptr<const GinJavaBridgeValue> gin_value; |
if (GinJavaBridgeValue::ContainsGinJavaBridgeValue(value)) { |
@@ -433,7 +440,8 @@ jvalue CoerceJavaScriptNullOrUndefinedToJavaValue(JNIEnv* env, |
jobject CoerceJavaScriptListToArray(JNIEnv* env, |
const base::Value* value, |
const JavaType& target_type, |
- const ObjectRefs& object_refs) { |
+ const ObjectRefs& object_refs, |
+ 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 |
@@ -461,7 +469,7 @@ jobject CoerceJavaScriptListToArray(JNIEnv* env, |
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); |
+ 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. |
@@ -478,7 +486,8 @@ jobject CoerceJavaScriptListToArray(JNIEnv* env, |
jobject CoerceJavaScriptDictionaryToArray(JNIEnv* env, |
const base::Value* value, |
const JavaType& target_type, |
- const ObjectRefs& object_refs) { |
+ const ObjectRefs& object_refs, |
+ GinJavaBridgeError* error) { |
DCHECK_EQ(JavaType::TypeArray, target_type.type); |
const JavaType& target_inner_type = *target_type.inner_type.get(); |
@@ -534,7 +543,7 @@ jobject CoerceJavaScriptDictionaryToArray(JNIEnv* env, |
dictionary_value->Get(key, &value_element); |
} |
jvalue element = CoerceJavaScriptValueToJavaValue( |
- env, value_element, target_inner_type, false, object_refs); |
+ 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. |
@@ -548,11 +557,29 @@ jobject CoerceJavaScriptDictionaryToArray(JNIEnv* env, |
return result; |
} |
+// Returns 'true' if it is possible to cast an object of class |src| to |
+// an object of class |dst|. |
+bool CanAssignClassVariables(JNIEnv* env, |
+ const ScopedJavaLocalRef<jclass>& dst, |
+ const ScopedJavaLocalRef<jclass>& src) { |
+ if (dst.is_null() || src.is_null()) |
+ return false; |
+ return env->IsAssignableFrom(src.obj(), dst.obj()) == JNI_TRUE; |
+} |
+ |
+ScopedJavaLocalRef<jclass> GetObjectClass( |
+ JNIEnv* env, |
+ const ScopedJavaLocalRef<jobject>& obj) { |
+ jclass clazz = env->GetObjectClass(obj.obj()); |
+ return ScopedJavaLocalRef<jclass>(env, clazz); |
+} |
+ |
jvalue CoerceJavaScriptObjectToJavaValue(JNIEnv* env, |
const base::Value* value, |
const JavaType& target_type, |
bool coerce_to_string, |
- const ObjectRefs& object_refs) { |
+ const ObjectRefs& object_refs, |
+ 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 |
@@ -565,7 +592,7 @@ jvalue CoerceJavaScriptObjectToJavaValue(JNIEnv* env, |
GinJavaBridgeValue::FromValue(value)); |
DCHECK(gin_value); |
DCHECK(gin_value->IsType(GinJavaBridgeValue::TYPE_OBJECT_ID)); |
- base::android::ScopedJavaLocalRef<jobject> obj; |
+ ScopedJavaLocalRef<jobject> obj; |
GinJavaBoundObject::ObjectID object_id; |
if (gin_value->GetAsObjectID(&object_id)) { |
ObjectRefs::const_iterator iter = object_refs.find(object_id); |
@@ -573,7 +600,17 @@ jvalue CoerceJavaScriptObjectToJavaValue(JNIEnv* env, |
obj.Reset(iter->second.get(env)); |
} |
} |
- result.l = obj.Release(); |
+ DCHECK(!target_type.class_jni_name.empty()); |
+ DCHECK(!obj.is_null()); |
+ if (CanAssignClassVariables( |
+ env, |
+ base::android::GetClass(env, target_type.JNIName().c_str()), |
+ GetObjectClass(env, obj))) { |
+ result.l = obj.Release(); |
+ } else { |
+ result.l = NULL; |
+ *error = kGinJavaBridgeNonAssignableTypes; |
+ } |
} else { |
// LIVECONNECT_COMPLIANCE: Existing behavior is to pass null. Spec |
// requires converting if the target type is |
@@ -610,10 +647,10 @@ jvalue CoerceJavaScriptObjectToJavaValue(JNIEnv* env, |
case JavaType::TypeArray: |
if (value->IsType(base::Value::TYPE_DICTIONARY)) { |
result.l = CoerceJavaScriptDictionaryToArray( |
- env, value, target_type, object_refs); |
+ env, value, target_type, object_refs, error); |
} else if (value->IsType(base::Value::TYPE_LIST)) { |
- result.l = |
- CoerceJavaScriptListToArray(env, value, target_type, object_refs); |
+ result.l = CoerceJavaScriptListToArray( |
+ env, value, target_type, object_refs, error); |
} else { |
result.l = NULL; |
} |
@@ -630,23 +667,24 @@ jvalue CoerceGinJavaBridgeValueToJavaValue(JNIEnv* env, |
const base::Value* value, |
const JavaType& target_type, |
bool coerce_to_string, |
- const ObjectRefs& object_refs) { |
+ const ObjectRefs& object_refs, |
+ GinJavaBridgeError* error) { |
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); |
+ env, value, target_type, coerce_to_string, error); |
case GinJavaBridgeValue::TYPE_NONFINITE: { |
float float_value; |
gin_value->GetAsNonFinite(&float_value); |
return CoerceJavaScriptDoubleToJavaValue( |
- env, float_value, target_type, coerce_to_string); |
+ 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); |
+ env, value, target_type, coerce_to_string, object_refs, error); |
default: |
NOTREACHED(); |
} |
@@ -670,35 +708,36 @@ jvalue CoerceJavaScriptValueToJavaValue(JNIEnv* env, |
const base::Value* value, |
const JavaType& target_type, |
bool coerce_to_string, |
- const ObjectRefs& object_refs) { |
+ const ObjectRefs& object_refs, |
+ 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->GetType()) { |
case base::Value::TYPE_INTEGER: |
return CoerceJavaScriptIntegerToJavaValue( |
- env, value, target_type, coerce_to_string); |
+ env, value, target_type, coerce_to_string, error); |
case base::Value::TYPE_DOUBLE: { |
double double_value; |
value->GetAsDouble(&double_value); |
return CoerceJavaScriptDoubleToJavaValue( |
- env, double_value, target_type, coerce_to_string); |
+ env, double_value, target_type, coerce_to_string, error); |
} |
case base::Value::TYPE_BOOLEAN: |
return CoerceJavaScriptBooleanToJavaValue( |
- env, value, target_type, coerce_to_string); |
+ env, value, target_type, coerce_to_string, error); |
case base::Value::TYPE_STRING: |
- return CoerceJavaScriptStringToJavaValue(env, value, target_type); |
+ return CoerceJavaScriptStringToJavaValue(env, value, target_type, error); |
case base::Value::TYPE_DICTIONARY: |
case base::Value::TYPE_LIST: |
return CoerceJavaScriptObjectToJavaValue( |
- env, value, target_type, coerce_to_string, object_refs); |
+ env, value, target_type, coerce_to_string, object_refs, error); |
case base::Value::TYPE_NULL: |
return CoerceJavaScriptNullOrUndefinedToJavaValue( |
- env, value, target_type, coerce_to_string); |
+ env, value, target_type, coerce_to_string, error); |
case base::Value::TYPE_BINARY: |
return CoerceGinJavaBridgeValueToJavaValue( |
- env, value, target_type, coerce_to_string, object_refs); |
+ env, value, target_type, coerce_to_string, object_refs, error); |
} |
NOTREACHED(); |
return jvalue(); |