| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/renderer_host/java/java_bound_object.h" | 5 #include "content/browser/renderer_host/java/java_bound_object.h" |
| 6 | 6 |
| 7 #include "base/android/jni_android.h" | 7 #include "base/android/jni_android.h" |
| 8 #include "base/android/jni_string.h" | 8 #include "base/android/jni_string.h" |
| 9 #include "base/memory/singleton.h" | 9 #include "base/memory/singleton.h" |
| 10 #include "base/string_number_conversions.h" | 10 #include "base/string_number_conversions.h" |
| (...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 390 case JavaType::TypeVoid: | 390 case JavaType::TypeVoid: |
| 391 // Conversion to void must never happen. | 391 // Conversion to void must never happen. |
| 392 case JavaType::TypeArray: | 392 case JavaType::TypeArray: |
| 393 case JavaType::TypeObject: | 393 case JavaType::TypeObject: |
| 394 // Not handled. | 394 // Not handled. |
| 395 NOTREACHED(); | 395 NOTREACHED(); |
| 396 } | 396 } |
| 397 return NULL; | 397 return NULL; |
| 398 } | 398 } |
| 399 | 399 |
| 400 // Note that this only handles primitive types and strings. | 400 // Sets the specified element of the supplied array to the value of the |
| 401 // supplied jvalue. Requires that the type of the array matches that of the |
| 402 // jvalue. Handles only primitive types and strings. Note that in the case of a |
| 403 // string, the array takes a new reference to the string object. |
| 401 void SetArrayElement(jobject array, | 404 void SetArrayElement(jobject array, |
| 402 const JavaType& type, | 405 const JavaType& type, |
| 403 jsize index, | 406 jsize index, |
| 404 const jvalue& value) { | 407 const jvalue& value) { |
| 405 JNIEnv* env = AttachCurrentThread(); | 408 JNIEnv* env = AttachCurrentThread(); |
| 406 switch (type.type) { | 409 switch (type.type) { |
| 407 case JavaType::TypeBoolean: | 410 case JavaType::TypeBoolean: |
| 408 env->SetBooleanArrayRegion(static_cast<jbooleanArray>(array), index, 1, | 411 env->SetBooleanArrayRegion(static_cast<jbooleanArray>(array), index, 1, |
| 409 &value.z); | 412 &value.z); |
| 410 break; | 413 break; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 447 // Not handled. | 450 // Not handled. |
| 448 NOTREACHED(); | 451 NOTREACHED(); |
| 449 } | 452 } |
| 450 base::android::CheckException(env); | 453 base::android::CheckException(env); |
| 451 } | 454 } |
| 452 | 455 |
| 453 jvalue CoerceJavaScriptValueToJavaValue(const NPVariant& variant, | 456 jvalue CoerceJavaScriptValueToJavaValue(const NPVariant& variant, |
| 454 const JavaType& target_type, | 457 const JavaType& target_type, |
| 455 bool coerce_to_string); | 458 bool coerce_to_string); |
| 456 | 459 |
| 460 void ReleaseJavaValueIfRequired(JNIEnv* env, |
| 461 jvalue* value, |
| 462 const JavaType& type) { |
| 463 if (type.type == JavaType::TypeString || |
| 464 type.type == JavaType::TypeObject || |
| 465 type.type == JavaType::TypeArray) { |
| 466 env->DeleteLocalRef(value->l); |
| 467 value->l = NULL; |
| 468 } |
| 469 } |
| 470 |
| 471 // Returns a new local reference to a Java array. |
| 457 jobject CoerceJavaScriptObjectToArray(const NPVariant& variant, | 472 jobject CoerceJavaScriptObjectToArray(const NPVariant& variant, |
| 458 const JavaType& target_type) { | 473 const JavaType& target_type) { |
| 459 DCHECK_EQ(JavaType::TypeArray, target_type.type); | 474 DCHECK_EQ(JavaType::TypeArray, target_type.type); |
| 460 NPObject* object = NPVARIANT_TO_OBJECT(variant); | 475 NPObject* object = NPVARIANT_TO_OBJECT(variant); |
| 461 DCHECK_NE(&JavaNPObject::kNPClass, object->_class); | 476 DCHECK_NE(&JavaNPObject::kNPClass, object->_class); |
| 462 | 477 |
| 463 const JavaType& target_inner_type = *target_type.inner_type.get(); | 478 const JavaType& target_inner_type = *target_type.inner_type.get(); |
| 464 // LIVECONNECT_COMPLIANCE: Existing behavior is to return null for | 479 // LIVECONNECT_COMPLIANCE: Existing behavior is to return null for |
| 465 // multi-dimensional arrays. Spec requires handling multi-demensional arrays. | 480 // multi-dimensional arrays. Spec requires handling multi-demensional arrays. |
| 466 if (target_inner_type.type == JavaType::TypeArray) { | 481 if (target_inner_type.type == JavaType::TypeArray) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 491 } else if (NPVARIANT_IS_DOUBLE(length_variant) | 506 } else if (NPVARIANT_IS_DOUBLE(length_variant) |
| 492 && NPVARIANT_TO_DOUBLE(length_variant) >= 0.0 | 507 && NPVARIANT_TO_DOUBLE(length_variant) >= 0.0 |
| 493 && NPVARIANT_TO_DOUBLE(length_variant) <= kint32max) { | 508 && NPVARIANT_TO_DOUBLE(length_variant) <= kint32max) { |
| 494 length = static_cast<jsize>(NPVARIANT_TO_DOUBLE(length_variant)); | 509 length = static_cast<jsize>(NPVARIANT_TO_DOUBLE(length_variant)); |
| 495 } | 510 } |
| 496 WebBindings::releaseVariantValue(&length_variant); | 511 WebBindings::releaseVariantValue(&length_variant); |
| 497 if (length == -1) { | 512 if (length == -1) { |
| 498 return NULL; | 513 return NULL; |
| 499 } | 514 } |
| 500 | 515 |
| 501 // Create the Java array. Note that we don't explicitly release the local | 516 // Create the Java array. |
| 502 // ref to the result or any of its elements. | |
| 503 // TODO(steveblock): Handle failure to create the array. | 517 // TODO(steveblock): Handle failure to create the array. |
| 504 jobject result = CreateJavaArray(target_inner_type, length); | 518 jobject result = CreateJavaArray(target_inner_type, length); |
| 505 NPVariant value_variant; | 519 NPVariant value_variant; |
| 520 JNIEnv* env = AttachCurrentThread(); |
| 506 for (jsize i = 0; i < length; ++i) { | 521 for (jsize i = 0; i < length; ++i) { |
| 507 // It seems that getProperty() will set the variant to type void on failure, | 522 // It seems that getProperty() will set the variant to type void on failure, |
| 508 // but this doesn't seem to be documented, so do it explicitly here for | 523 // but this doesn't seem to be documented, so do it explicitly here for |
| 509 // safety. | 524 // safety. |
| 510 VOID_TO_NPVARIANT(value_variant); | 525 VOID_TO_NPVARIANT(value_variant); |
| 511 // If this fails, for example due to a missing element, we simply treat the | 526 // If this fails, for example due to a missing element, we simply treat the |
| 512 // value as JavaScript undefined. | 527 // value as JavaScript undefined. |
| 513 WebBindings::getProperty(0, object, WebBindings::getIntIdentifier(i), | 528 WebBindings::getProperty(0, object, WebBindings::getIntIdentifier(i), |
| 514 &value_variant); | 529 &value_variant); |
| 515 SetArrayElement(result, target_inner_type, i, | 530 jvalue element = CoerceJavaScriptValueToJavaValue(value_variant, |
| 516 CoerceJavaScriptValueToJavaValue(value_variant, | 531 target_inner_type, |
| 517 target_inner_type, | 532 false); |
| 518 false)); | 533 SetArrayElement(result, target_inner_type, i, element); |
| 534 // CoerceJavaScriptValueToJavaValue() creates new local references to |
| 535 // strings, objects and arrays. Of these, only strings can occur here. |
| 536 // SetArrayElement() causes the array to take its own reference to the |
| 537 // string, so we can now release the local reference. |
| 538 DCHECK_NE(JavaType::TypeObject, target_inner_type.type); |
| 539 DCHECK_NE(JavaType::TypeArray, target_inner_type.type); |
| 540 ReleaseJavaValueIfRequired(env, &element, target_inner_type); |
| 519 WebBindings::releaseVariantValue(&value_variant); | 541 WebBindings::releaseVariantValue(&value_variant); |
| 520 } | 542 } |
| 521 | 543 |
| 522 return result; | 544 return result; |
| 523 } | 545 } |
| 524 | 546 |
| 525 jvalue CoerceJavaScriptObjectToJavaValue(const NPVariant& variant, | 547 jvalue CoerceJavaScriptObjectToJavaValue(const NPVariant& variant, |
| 526 const JavaType& target_type, | 548 const JavaType& target_type, |
| 527 bool coerce_to_string) { | 549 bool coerce_to_string) { |
| 528 // This covers both JavaScript objects (including arrays) and Java objects. | 550 // This covers both JavaScript objects (including arrays) and Java objects. |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 637 NOTREACHED(); | 659 NOTREACHED(); |
| 638 break; | 660 break; |
| 639 } | 661 } |
| 640 return result; | 662 return result; |
| 641 } | 663 } |
| 642 | 664 |
| 643 // coerce_to_string means that we should try to coerce all JavaScript values to | 665 // coerce_to_string means that we should try to coerce all JavaScript values to |
| 644 // strings when required, rather than simply converting to NULL. This is used | 666 // strings when required, rather than simply converting to NULL. This is used |
| 645 // to maintain current behaviour, which differs slightly depending upon whether | 667 // to maintain current behaviour, which differs slightly depending upon whether |
| 646 // or not the coercion in question is for an array element. | 668 // or not the coercion in question is for an array element. |
| 669 // |
| 670 // Note that the jvalue returned by this method may contain a new local |
| 671 // reference to an object (string, object or array). This must be released by |
| 672 // the caller. |
| 647 jvalue CoerceJavaScriptValueToJavaValue(const NPVariant& variant, | 673 jvalue CoerceJavaScriptValueToJavaValue(const NPVariant& variant, |
| 648 const JavaType& target_type, | 674 const JavaType& target_type, |
| 649 bool coerce_to_string) { | 675 bool coerce_to_string) { |
| 650 // Note that in all these conversions, the relevant field of the jvalue must | 676 // Note that in all these conversions, the relevant field of the jvalue must |
| 651 // always be explicitly set, as jvalue does not initialize its fields. | 677 // always be explicitly set, as jvalue does not initialize its fields. |
| 652 | 678 |
| 653 // Some of these methods create new Java Strings. Note that we don't | |
| 654 // explicitly release the local ref to these new objects, as there's no simple | |
| 655 // way to do so. | |
| 656 switch (variant.type) { | 679 switch (variant.type) { |
| 657 case NPVariantType_Int32: | 680 case NPVariantType_Int32: |
| 658 case NPVariantType_Double: | 681 case NPVariantType_Double: |
| 659 return CoerceJavaScriptNumberToJavaValue(variant, target_type, | 682 return CoerceJavaScriptNumberToJavaValue(variant, target_type, |
| 660 coerce_to_string); | 683 coerce_to_string); |
| 661 case NPVariantType_Bool: | 684 case NPVariantType_Bool: |
| 662 return CoerceJavaScriptBooleanToJavaValue(variant, target_type, | 685 return CoerceJavaScriptBooleanToJavaValue(variant, target_type, |
| 663 coerce_to_string); | 686 coerce_to_string); |
| 664 case NPVariantType_String: | 687 case NPVariantType_String: |
| 665 return CoerceJavaScriptStringToJavaValue(variant, target_type); | 688 return CoerceJavaScriptStringToJavaValue(variant, target_type); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 738 std::vector<jvalue> parameters(arg_count); | 761 std::vector<jvalue> parameters(arg_count); |
| 739 for (size_t i = 0; i < arg_count; ++i) { | 762 for (size_t i = 0; i < arg_count; ++i) { |
| 740 parameters[i] = CoerceJavaScriptValueToJavaValue(args[i], | 763 parameters[i] = CoerceJavaScriptValueToJavaValue(args[i], |
| 741 method->parameter_type(i), | 764 method->parameter_type(i), |
| 742 true); | 765 true); |
| 743 } | 766 } |
| 744 | 767 |
| 745 // Call | 768 // Call |
| 746 *result = CallJNIMethod(java_object_.obj(), method->return_type(), | 769 *result = CallJNIMethod(java_object_.obj(), method->return_type(), |
| 747 method->id(), ¶meters[0]); | 770 method->id(), ¶meters[0]); |
| 771 |
| 772 // Now that we're done with the jvalue, release any local references created |
| 773 // by CoerceJavaScriptValueToJavaValue(). |
| 774 JNIEnv* env = AttachCurrentThread(); |
| 775 for (size_t i = 0; i < arg_count; ++i) { |
| 776 ReleaseJavaValueIfRequired(env, ¶meters[i], method->parameter_type(i)); |
| 777 } |
| 778 |
| 748 return true; | 779 return true; |
| 749 } | 780 } |
| 750 | 781 |
| 751 void JavaBoundObject::EnsureMethodsAreSetUp() const { | 782 void JavaBoundObject::EnsureMethodsAreSetUp() const { |
| 752 if (!methods_.empty()) { | 783 if (!methods_.empty()) { |
| 753 return; | 784 return; |
| 754 } | 785 } |
| 755 | 786 |
| 756 JNIEnv* env = AttachCurrentThread(); | 787 JNIEnv* env = AttachCurrentThread(); |
| 757 ScopedJavaLocalRef<jclass> clazz(env, static_cast<jclass>( | 788 ScopedJavaLocalRef<jclass> clazz(env, static_cast<jclass>( |
| (...skipping 11 matching lines...) Expand all Loading... |
| 769 size_t num_methods = env->GetArrayLength(methods.obj()); | 800 size_t num_methods = env->GetArrayLength(methods.obj()); |
| 770 DCHECK(num_methods) << "Java objects always have public methods"; | 801 DCHECK(num_methods) << "Java objects always have public methods"; |
| 771 for (size_t i = 0; i < num_methods; ++i) { | 802 for (size_t i = 0; i < num_methods; ++i) { |
| 772 ScopedJavaLocalRef<jobject> java_method( | 803 ScopedJavaLocalRef<jobject> java_method( |
| 773 env, | 804 env, |
| 774 env->GetObjectArrayElement(methods.obj(), i)); | 805 env->GetObjectArrayElement(methods.obj(), i)); |
| 775 JavaMethod* method = new JavaMethod(java_method); | 806 JavaMethod* method = new JavaMethod(java_method); |
| 776 methods_.insert(std::make_pair(method->name(), method)); | 807 methods_.insert(std::make_pair(method->name(), method)); |
| 777 } | 808 } |
| 778 } | 809 } |
| OLD | NEW |