1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/browser/android/java/gin_java_script_to_java_types_coercion.h" 6 7 #include <unistd.h> 8 9 #include "base/android/jni_android.h" 10 #include "base/android/jni_string.h" 11 #include "base/strings/string_number_conversions.h" 12 #include "base/strings/stringprintf.h" 13 #include "base/strings/utf_string_conversions.h" 14 #include "content/common/android/gin_java_bridge_value.h" 15 #include "third_party/WebKit/public/platform/WebString.h" 16 17 using base::android::ScopedJavaLocalRef; 18 19 namespace content { 20 21 namespace { 22 23 const char kJavaLangString[] = "java/lang/String"; 24 const char kUndefined[] = "undefined"; 25 26 // This is an intermediate solution until we fix http://crbug.com/391492. 27 jstring ConvertUTF8ToJString(JNIEnv* env, const std::string& string) { 28 base::string16 utf16( 29 blink::WebString::fromUTF8(string.c_str(), string.size())); 30 return env->NewString(utf16.data(), utf16.length()); 31 } 32 33 double RoundDoubleTowardsZero(const double& x) { 34 if (std::isnan(x)) { 35 return 0.0; 36 } 37 return x > 0.0 ? floor(x) : ceil(x); 38 } 39 40 // Rounds to jlong using Java's type conversion rules. 41 jlong RoundDoubleToLong(const double& x) { 42 double intermediate = RoundDoubleTowardsZero(x); 43 // The int64 limits can not be converted exactly to double values, so we 44 // compare to custom constants. kint64max is 2^63 - 1, but the spacing 45 // between double values in the the range 2^62 to 2^63 is 2^10. The cast is 46 // required to silence a spurious gcc warning for integer overflow. 47 const int64 kLimit = (GG_INT64_C(1) << 63) - static_cast<uint64>(1 << 10); 48 DCHECK(kLimit > 0); 49 const double kLargestDoubleLessThanInt64Max = kLimit; 50 const double kSmallestDoubleGreaterThanInt64Min = -kLimit; 51 if (intermediate > kLargestDoubleLessThanInt64Max) { 52 return kint64max; 53 } 54 if (intermediate < kSmallestDoubleGreaterThanInt64Min) { 55 return kint64min; 56 } 57 return static_cast<jlong>(intermediate); 58 } 59 60 // Rounds to jint using Java's type conversion rules. 61 jint RoundDoubleToInt(const double& x) { 62 double intermediate = RoundDoubleTowardsZero(x); 63 // The int32 limits cast exactly to double values. 64 intermediate = std::min(intermediate, static_cast<double>(kint32max)); 65 intermediate = std::max(intermediate, static_cast<double>(kint32min)); 66 return static_cast<jint>(intermediate); 67 } 68 69 jvalue CoerceJavaScriptIntegerToJavaValue(JNIEnv* env, 70 const base::Value* value, 71 const JavaType& target_type, 72 bool coerce_to_string, 73 GinJavaBridgeError* error) { 74 // See http://jdk6.java.net/plugin2/liveconnect/#JS_NUMBER_VALUES. 75 76 // For conversion to numeric types, we need to replicate Java's type 77 // conversion rules. This requires that for integer values, we simply discard 78 // all but the lowest n buts, where n is the number of bits in the target 79 // type. 80 jvalue result; 81 int int_value; 82 value->GetAsInteger(&int_value); 83 switch (target_type.type) { 84 case JavaType::TypeByte: 85 result.b = static_cast<jbyte>(int_value); 86 break; 87 case JavaType::TypeChar: 88 result.c = static_cast<jchar>(int_value); 89 break; 90 case JavaType::TypeShort: 91 result.s = static_cast<jshort>(int_value); 92 break; 93 case JavaType::TypeInt: 94 result.i = int_value; 95 break; 96 case JavaType::TypeLong: 97 result.j = int_value; 98 break; 99 case JavaType::TypeFloat: 100 result.f = int_value; 101 break; 102 case JavaType::TypeDouble: 103 result.d = int_value; 104 break; 105 case JavaType::TypeObject: 106 // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to null. Spec 107 // requires handling object equivalents of primitive types. 108 result.l = NULL; 109 break; 110 case JavaType::TypeString: 111 result.l = coerce_to_string 112 ? ConvertUTF8ToJString(env, base::Int64ToString(int_value)) 113 : NULL; 114 break; 115 case JavaType::TypeBoolean: 116 // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to false. Spec 117 // requires converting to false for 0 or NaN, true otherwise. 118 result.z = JNI_FALSE; 119 break; 120 case JavaType::TypeArray: 121 // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to null. Spec 122 // requires raising a JavaScript exception. 123 result.l = NULL; 124 break; 125 case JavaType::TypeVoid: 126 // Conversion to void must never happen. 127 NOTREACHED(); 128 break; 129 } 130 return result; 131 } 132 133 jvalue CoerceJavaScriptDoubleToJavaValue(JNIEnv* env, 134 double double_value, 135 const JavaType& target_type, 136 bool coerce_to_string, 137 GinJavaBridgeError* error) { 138 // See http://jdk6.java.net/plugin2/liveconnect/#JS_NUMBER_VALUES. 139 // For conversion to numeric types, we need to replicate Java's type 140 // conversion rules. 141 jvalue result; 142 switch (target_type.type) { 143 case JavaType::TypeByte: 144 result.b = static_cast<jbyte>(RoundDoubleToInt(double_value)); 145 break; 146 case JavaType::TypeChar: 147 // LIVECONNECT_COMPLIANCE: Existing behavior is to convert double to 0. 148 // Spec requires converting doubles similarly to how we convert doubles to 149 // other numeric types. 150 result.c = 0; 151 break; 152 case JavaType::TypeShort: 153 result.s = static_cast<jshort>(RoundDoubleToInt(double_value)); 154 break; 155 case JavaType::TypeInt: 156 result.i = RoundDoubleToInt(double_value); 157 break; 158 case JavaType::TypeLong: 159 result.j = RoundDoubleToLong(double_value); 160 break; 161 case JavaType::TypeFloat: 162 result.f = static_cast<jfloat>(double_value); 163 break; 164 case JavaType::TypeDouble: 165 result.d = double_value; 166 break; 167 case JavaType::TypeObject: 168 // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to null. Spec 169 // requires handling object equivalents of primitive types. 170 result.l = NULL; 171 break; 172 case JavaType::TypeString: 173 result.l = coerce_to_string 174 ? ConvertUTF8ToJString( 175 env, base::StringPrintf("%.6lg", double_value)) 176 : NULL; 177 break; 178 case JavaType::TypeBoolean: 179 // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to false. Spec 180 // requires converting to false for 0 or NaN, true otherwise. 181 result.z = JNI_FALSE; 182 break; 183 case JavaType::TypeArray: 184 // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to null. Spec 185 // requires raising a JavaScript exception. 186 result.l = NULL; 187 break; 188 case JavaType::TypeVoid: 189 // Conversion to void must never happen. 190 NOTREACHED(); 191 break; 192 } 193 return result; 194 } 195 196 jvalue CoerceJavaScriptBooleanToJavaValue(JNIEnv* env, 197 const base::Value* value, 198 const JavaType& target_type, 199 bool coerce_to_string, 200 GinJavaBridgeError* error) { 201 // See http://jdk6.java.net/plugin2/liveconnect/#JS_BOOLEAN_VALUES. 202 bool boolean_value; 203 value->GetAsBoolean(&boolean_value); 204 jvalue result; 205 switch (target_type.type) { 206 case JavaType::TypeBoolean: 207 result.z = boolean_value ? JNI_TRUE : JNI_FALSE; 208 break; 209 case JavaType::TypeObject: 210 // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec 211 // requires handling java.lang.Boolean and java.lang.Object. 212 result.l = NULL; 213 break; 214 case JavaType::TypeString: 215 result.l = coerce_to_string ? ConvertUTF8ToJString( 216 env, boolean_value ? "true" : "false") 217 : NULL; 218 break; 219 case JavaType::TypeByte: 220 case JavaType::TypeChar: 221 case JavaType::TypeShort: 222 case JavaType::TypeInt: 223 case JavaType::TypeLong: 224 case JavaType::TypeFloat: 225 case JavaType::TypeDouble: { 226 // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to 0. Spec 227 // requires converting to 0 or 1. 228 jvalue null_value = {0}; 229 result = null_value; 230 break; 231 } 232 case JavaType::TypeArray: 233 // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec 234 // requires raising a JavaScript exception. 235 result.l = NULL; 236 break; 237 case JavaType::TypeVoid: 238 // Conversion to void must never happen. 239 NOTREACHED(); 240 break; 241 } 242 return result; 243 } 244 245 jvalue CoerceJavaScriptStringToJavaValue(JNIEnv* env, 246 const base::Value* value, 247 const JavaType& target_type, 248 GinJavaBridgeError* error) { 249 // See http://jdk6.java.net/plugin2/liveconnect/#JS_STRING_VALUES. 250 jvalue result; 251 switch (target_type.type) { 252 case JavaType::TypeString: { 253 std::string string_result; 254 value->GetAsString(&string_result); 255 result.l = ConvertUTF8ToJString(env, string_result); 256 break; 257 } 258 case JavaType::TypeObject: 259 // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec 260 // requires handling java.lang.Object. 261 result.l = NULL; 262 break; 263 case JavaType::TypeByte: 264 case JavaType::TypeShort: 265 case JavaType::TypeInt: 266 case JavaType::TypeLong: 267 case JavaType::TypeFloat: 268 case JavaType::TypeDouble: { 269 // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to 0. Spec 270 // requires using valueOf() method of corresponding object type. 271 jvalue null_value = {0}; 272 result = null_value; 273 break; 274 } 275 case JavaType::TypeChar: 276 // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to 0. Spec 277 // requires using java.lang.Short.decode(). 278 result.c = 0; 279 break; 280 case JavaType::TypeBoolean: 281 // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to false. Spec 282 // requires converting the empty string to false, otherwise true. 283 result.z = JNI_FALSE; 284 break; 285 case JavaType::TypeArray: 286 // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec 287 // requires raising a JavaScript exception. 288 result.l = NULL; 289 break; 290 case JavaType::TypeVoid: 291 // Conversion to void must never happen. 292 NOTREACHED(); 293 break; 294 } 295 return result; 296 } 297 298 // Note that this only handles primitive types and strings. 299 jobject CreateJavaArray(JNIEnv* env, const JavaType& type, jsize length) { 300 switch (type.type) { 301 case JavaType::TypeBoolean: 302 return env->NewBooleanArray(length); 303 case JavaType::TypeByte: 304 return env->NewByteArray(length); 305 case JavaType::TypeChar: 306 return env->NewCharArray(length); 307 case JavaType::TypeShort: 308 return env->NewShortArray(length); 309 case JavaType::TypeInt: 310 return env->NewIntArray(length); 311 case JavaType::TypeLong: 312 return env->NewLongArray(length); 313 case JavaType::TypeFloat: 314 return env->NewFloatArray(length); 315 case JavaType::TypeDouble: 316 return env->NewDoubleArray(length); 317 case JavaType::TypeString: { 318 ScopedJavaLocalRef<jclass> clazz( 319 base::android::GetClass(env, kJavaLangString)); 320 return env->NewObjectArray(length, clazz.obj(), NULL); 321 } 322 case JavaType::TypeVoid: 323 // Conversion to void must never happen. 324 case JavaType::TypeArray: 325 case JavaType::TypeObject: 326 // Not handled. 327 NOTREACHED(); 328 } 329 return NULL; 330 } 331 332 // Sets the specified element of the supplied array to the value of the 333 // supplied jvalue. Requires that the type of the array matches that of the 334 // jvalue. Handles only primitive types and strings. Note that in the case of a 335 // string, the array takes a new reference to the string object. 336 void SetArrayElement(JNIEnv* env, 337 jobject array, 338 const JavaType& type, 339 jsize index, 340 const jvalue& value) { 341 switch (type.type) { 342 case JavaType::TypeBoolean: 343 env->SetBooleanArrayRegion(static_cast<jbooleanArray>(array), index, 1, 344 &value.z); 345 break; 346 case JavaType::TypeByte: 347 env->SetByteArrayRegion(static_cast<jbyteArray>(array), index, 1, 348 &value.b); 349 break; 350 case JavaType::TypeChar: 351 env->SetCharArrayRegion(static_cast<jcharArray>(array), index, 1, 352 &value.c); 353 break; 354 case JavaType::TypeShort: 355 env->SetShortArrayRegion(static_cast<jshortArray>(array), index, 1, 356 &value.s); 357 break; 358 case JavaType::TypeInt: 359 env->SetIntArrayRegion(static_cast<jintArray>(array), index, 1, 360 &value.i); 361 break; 362 case JavaType::TypeLong: 363 env->SetLongArrayRegion(static_cast<jlongArray>(array), index, 1, 364 &value.j); 365 break; 366 case JavaType::TypeFloat: 367 env->SetFloatArrayRegion(static_cast<jfloatArray>(array), index, 1, 368 &value.f); 369 break; 370 case JavaType::TypeDouble: 371 env->SetDoubleArrayRegion(static_cast<jdoubleArray>(array), index, 1, 372 &value.d); 373 break; 374 case JavaType::TypeString: 375 env->SetObjectArrayElement(static_cast<jobjectArray>(array), index, 376 value.l); 377 break; 378 case JavaType::TypeVoid: 379 // Conversion to void must never happen. 380 case JavaType::TypeArray: 381 case JavaType::TypeObject: 382 // Not handled. 383 NOTREACHED(); 384 } 385 base::android::CheckException(env); 386 } 387 388 jvalue CoerceJavaScriptNullOrUndefinedToJavaValue(JNIEnv* env, 389 const base::Value* value, 390 const JavaType& target_type, 391 bool coerce_to_string, 392 GinJavaBridgeError* error) { 393 bool is_undefined = false; 394 scoped_ptr<const GinJavaBridgeValue> gin_value; 395 if (GinJavaBridgeValue::ContainsGinJavaBridgeValue(value)) { 396 gin_value = GinJavaBridgeValue::FromValue(value); 397 if (gin_value->IsType(GinJavaBridgeValue::TYPE_UNDEFINED)) { 398 is_undefined = true; 399 } 400 } 401 jvalue result; 402 switch (target_type.type) { 403 case JavaType::TypeObject: 404 result.l = NULL; 405 break; 406 case JavaType::TypeString: 407 // LIVECONNECT_COMPLIANCE: Existing behavior is to convert undefined to 408 // "undefined". Spec requires converting undefined to NULL. 409 result.l = (coerce_to_string && is_undefined) 410 ? ConvertUTF8ToJString(env, kUndefined) 411 : NULL; 412 break; 413 case JavaType::TypeByte: 414 case JavaType::TypeChar: 415 case JavaType::TypeShort: 416 case JavaType::TypeInt: 417 case JavaType::TypeLong: 418 case JavaType::TypeFloat: 419 case JavaType::TypeDouble: { 420 jvalue null_value = {0}; 421 result = null_value; 422 break; 423 } 424 case JavaType::TypeBoolean: 425 result.z = JNI_FALSE; 426 break; 427 case JavaType::TypeArray: 428 // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec 429 // requires raising a JavaScript exception. 430 result.l = NULL; 431 break; 432 case JavaType::TypeVoid: 433 // Conversion to void must never happen. 434 NOTREACHED(); 435 break; 436 } 437 return result; 438 } 439 440 jobject CoerceJavaScriptListToArray(JNIEnv* env, 441 const base::Value* value, 442 const JavaType& target_type, 443 const ObjectRefs& object_refs, 444 GinJavaBridgeError* error) { 445 DCHECK_EQ(JavaType::TypeArray, target_type.type); 446 const JavaType& target_inner_type = *target_type.inner_type.get(); 447 // LIVECONNECT_COMPLIANCE: Existing behavior is to return null for 448 // multi-dimensional arrays. Spec requires handling multi-demensional arrays. 449 if (target_inner_type.type == JavaType::TypeArray) { 450 return NULL; 451 } 452 453 // LIVECONNECT_COMPLIANCE: Existing behavior is to return null for object 454 // arrays. Spec requires handling object arrays. 455 if (target_inner_type.type == JavaType::TypeObject) { 456 return NULL; 457 } 458 459 const base::ListValue* list_value; 460 value->GetAsList(&list_value); 461 // Create the Java array. 462 jsize length = static_cast<jsize>(list_value->GetSize()); 463 jobject result = CreateJavaArray(env, target_inner_type, length); 464 if (!result) { 465 return NULL; 466 } 467 scoped_ptr<base::Value> null_value(base::Value::CreateNullValue()); 468 for (jsize i = 0; i < length; ++i) { 469 const base::Value* value_element = null_value.get(); 470 list_value->Get(i, &value_element); 471 jvalue element = CoerceJavaScriptValueToJavaValue( 472 env, value_element, target_inner_type, false, object_refs, error); 473 SetArrayElement(env, result, target_inner_type, i, element); 474 // CoerceJavaScriptValueToJavaValue() creates new local references to 475 // strings, objects and arrays. Of these, only strings can occur here. 476 // SetArrayElement() causes the array to take its own reference to the 477 // string, so we can now release the local reference. 478 DCHECK_NE(JavaType::TypeObject, target_inner_type.type); 479 DCHECK_NE(JavaType::TypeArray, target_inner_type.type); 480 ReleaseJavaValueIfRequired(env, &element, target_inner_type); 481 } 482 483 return result; 484 } 485 486 jobject CoerceJavaScriptDictionaryToArray(JNIEnv* env, 487 const base::Value* value, 488 const JavaType& target_type, 489 const ObjectRefs& object_refs, 490 GinJavaBridgeError* error) { 491 DCHECK_EQ(JavaType::TypeArray, target_type.type); 492 493 const JavaType& target_inner_type = *target_type.inner_type.get(); 494 // LIVECONNECT_COMPLIANCE: Existing behavior is to return null for 495 // multi-dimensional arrays. Spec requires handling multi-demensional arrays. 496 if (target_inner_type.type == JavaType::TypeArray) { 497 return NULL; 498 } 499 500 // LIVECONNECT_COMPLIANCE: Existing behavior is to return null for object 501 // arrays. Spec requires handling object arrays. 502 if (target_inner_type.type == JavaType::TypeObject) { 503 return NULL; 504 } 505 506 const base::DictionaryValue* dictionary_value; 507 value->GetAsDictionary(&dictionary_value); 508 const base::Value* length_value; 509 // If the object does not have a length property, return null. 510 if (!dictionary_value->Get("length", &length_value)) { 511 return NULL; 512 } 513 514 // If the length property does not have numeric type, or is outside the valid 515 // range for a Java array length, return null. 516 jsize length = -1; 517 if (length_value->IsType(base::Value::TYPE_INTEGER)) { 518 int int_length; 519 length_value->GetAsInteger(&int_length); 520 if (int_length >= 0 && int_length <= kint32max) { 521 length = static_cast<jsize>(int_length); 522 } 523 } else if (length_value->IsType(base::Value::TYPE_DOUBLE)) { 524 double double_length; 525 length_value->GetAsDouble(&double_length); 526 if (double_length >= 0.0 && double_length <= kint32max) { 527 length = static_cast<jsize>(double_length); 528 } 529 } 530 if (length == -1) { 531 return NULL; 532 } 533 534 jobject result = CreateJavaArray(env, target_inner_type, length); 535 if (!result) { 536 return NULL; 537 } 538 scoped_ptr<base::Value> null_value(base::Value::CreateNullValue()); 539 for (jsize i = 0; i < length; ++i) { 540 const std::string key(base::IntToString(i)); 541 const base::Value* value_element = null_value.get(); 542 if (dictionary_value->HasKey(key)) { 543 dictionary_value->Get(key, &value_element); 544 } 545 jvalue element = CoerceJavaScriptValueToJavaValue( 546 env, value_element, target_inner_type, false, object_refs, error); 547 SetArrayElement(env, result, target_inner_type, i, element); 548 // CoerceJavaScriptValueToJavaValue() creates new local references to 549 // strings, objects and arrays. Of these, only strings can occur here. 550 // SetArrayElement() causes the array to take its own reference to the 551 // string, so we can now release the local reference. 552 DCHECK_NE(JavaType::TypeObject, target_inner_type.type); 553 DCHECK_NE(JavaType::TypeArray, target_inner_type.type); 554 ReleaseJavaValueIfRequired(env, &element, target_inner_type); 555 } 556 557 return result; 558 } 559 560 // Returns 'true' if it is possible to cast an object of class |src| to 561 // an object of class |dst|. 562 bool CanAssignClassVariables(JNIEnv* env, 563 const ScopedJavaLocalRef<jclass>& dst, 564 const ScopedJavaLocalRef<jclass>& src) { 565 if (dst.is_null() || src.is_null()) 566 return false; 567 return env->IsAssignableFrom(src.obj(), dst.obj()) == JNI_TRUE; 568 } 569 570 ScopedJavaLocalRef<jclass> GetObjectClass( 571 JNIEnv* env, 572 const ScopedJavaLocalRef<jobject>& obj) { 573 jclass clazz = env->GetObjectClass(obj.obj()); 574 return ScopedJavaLocalRef<jclass>(env, clazz); 575 } 576 577 jvalue CoerceJavaScriptObjectToJavaValue(JNIEnv* env, 578 const base::Value* value, 579 const JavaType& target_type, 580 bool coerce_to_string, 581 const ObjectRefs& object_refs, 582 GinJavaBridgeError* error) { 583 // This covers both JavaScript objects (including arrays) and Java objects. 584 // See http://jdk6.java.net/plugin2/liveconnect/#JS_OTHER_OBJECTS, 585 // http://jdk6.java.net/plugin2/liveconnect/#JS_ARRAY_VALUES and 586 // http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_OBJECTS 587 jvalue result; 588 switch (target_type.type) { 589 case JavaType::TypeObject: { 590 if (GinJavaBridgeValue::ContainsGinJavaBridgeValue(value)) { 591 scoped_ptr<const GinJavaBridgeValue> gin_value( 592 GinJavaBridgeValue::FromValue(value)); 593 DCHECK(gin_value); 594 DCHECK(gin_value->IsType(GinJavaBridgeValue::TYPE_OBJECT_ID)); 595 ScopedJavaLocalRef<jobject> obj; 596 GinJavaBoundObject::ObjectID object_id; 597 if (gin_value->GetAsObjectID(&object_id)) { 598 ObjectRefs::const_iterator iter = object_refs.find(object_id); 599 if (iter != object_refs.end()) { 600 obj.Reset(iter->second.get(env)); 601 } 602 } 603 DCHECK(!target_type.class_jni_name.empty()); 604 DCHECK(!obj.is_null()); 605 if (CanAssignClassVariables( 606 env, 607 base::android::GetClass(env, target_type.JNIName().c_str()), 608 GetObjectClass(env, obj))) { 609 result.l = obj.Release(); 610 } else { 611 result.l = NULL; 612 *error = kGinJavaBridgeNonAssignableTypes; 613 } 614 } else { 615 // LIVECONNECT_COMPLIANCE: Existing behavior is to pass null. Spec 616 // requires converting if the target type is 617 // netscape.javascript.JSObject, otherwise raising a JavaScript 618 // exception. 619 result.l = NULL; 620 } 621 break; 622 } 623 case JavaType::TypeString: 624 // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to 625 // "undefined". Spec requires calling toString() on the Java object. 626 result.l = 627 coerce_to_string ? ConvertUTF8ToJString(env, kUndefined) : NULL; 628 break; 629 case JavaType::TypeByte: 630 case JavaType::TypeShort: 631 case JavaType::TypeInt: 632 case JavaType::TypeLong: 633 case JavaType::TypeFloat: 634 case JavaType::TypeDouble: 635 case JavaType::TypeChar: { 636 // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to 0. Spec 637 // requires raising a JavaScript exception. 638 jvalue null_value = {0}; 639 result = null_value; 640 break; 641 } 642 case JavaType::TypeBoolean: 643 // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to false. Spec 644 // requires raising a JavaScript exception. 645 result.z = JNI_FALSE; 646 break; 647 case JavaType::TypeArray: 648 if (value->IsType(base::Value::TYPE_DICTIONARY)) { 649 result.l = CoerceJavaScriptDictionaryToArray( 650 env, value, target_type, object_refs, error); 651 } else if (value->IsType(base::Value::TYPE_LIST)) { 652 result.l = CoerceJavaScriptListToArray( 653 env, value, target_type, object_refs, error); 654 } else { 655 result.l = NULL; 656 } 657 break; 658 case JavaType::TypeVoid: 659 // Conversion to void must never happen. 660 NOTREACHED(); 661 break; 662 } 663 return result; 664 } 665 666 jvalue CoerceGinJavaBridgeValueToJavaValue(JNIEnv* env, 667 const base::Value* value, 668 const JavaType& target_type, 669 bool coerce_to_string, 670 const ObjectRefs& object_refs, 671 GinJavaBridgeError* error) { 672 DCHECK(GinJavaBridgeValue::ContainsGinJavaBridgeValue(value)); 673 scoped_ptr<const GinJavaBridgeValue> gin_value( 674 GinJavaBridgeValue::FromValue(value)); 675 switch (gin_value->GetType()) { 676 case GinJavaBridgeValue::TYPE_UNDEFINED: 677 return CoerceJavaScriptNullOrUndefinedToJavaValue( 678 env, value, target_type, coerce_to_string, error); 679 case GinJavaBridgeValue::TYPE_NONFINITE: { 680 float float_value; 681 gin_value->GetAsNonFinite(&float_value); 682 return CoerceJavaScriptDoubleToJavaValue( 683 env, float_value, target_type, coerce_to_string, error); 684 } 685 case GinJavaBridgeValue::TYPE_OBJECT_ID: 686 return CoerceJavaScriptObjectToJavaValue( 687 env, value, target_type, coerce_to_string, object_refs, error); 688 default: 689 NOTREACHED(); 690 } 691 return jvalue(); 692 } 693 694 } // namespace 695 696 697 void ReleaseJavaValueIfRequired(JNIEnv* env, 698 jvalue* value, 699 const JavaType& type) { 700 if (type.type == JavaType::TypeString || type.type == JavaType::TypeObject || 701 type.type == JavaType::TypeArray) { 702 env->DeleteLocalRef(value->l); 703 value->l = NULL; 704 } 705 } 706 707 jvalue CoerceJavaScriptValueToJavaValue(JNIEnv* env, 708 const base::Value* value, 709 const JavaType& target_type, 710 bool coerce_to_string, 711 const ObjectRefs& object_refs, 712 GinJavaBridgeError* error) { 713 // Note that in all these conversions, the relevant field of the jvalue must 714 // always be explicitly set, as jvalue does not initialize its fields. 715 716 switch (value->GetType()) { 717 case base::Value::TYPE_INTEGER: 718 return CoerceJavaScriptIntegerToJavaValue( 719 env, value, target_type, coerce_to_string, error); 720 case base::Value::TYPE_DOUBLE: { 721 double double_value; 722 value->GetAsDouble(&double_value); 723 return CoerceJavaScriptDoubleToJavaValue( 724 env, double_value, target_type, coerce_to_string, error); 725 } 726 case base::Value::TYPE_BOOLEAN: 727 return CoerceJavaScriptBooleanToJavaValue( 728 env, value, target_type, coerce_to_string, error); 729 case base::Value::TYPE_STRING: 730 return CoerceJavaScriptStringToJavaValue(env, value, target_type, error); 731 case base::Value::TYPE_DICTIONARY: 732 case base::Value::TYPE_LIST: 733 return CoerceJavaScriptObjectToJavaValue( 734 env, value, target_type, coerce_to_string, object_refs, error); 735 case base::Value::TYPE_NULL: 736 return CoerceJavaScriptNullOrUndefinedToJavaValue( 737 env, value, target_type, coerce_to_string, error); 738 case base::Value::TYPE_BINARY: 739 return CoerceGinJavaBridgeValueToJavaValue( 740 env, value, target_type, coerce_to_string, object_refs, error); 741 } 742 NOTREACHED(); 743 return jvalue(); 744 } 745 746 } // namespace content 747