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, jvalue* value, | |
joth
2012/03/22 13:20:48
nit: one param per line.
(if you want, you could g
| |
461 const JavaType& type) { | |
462 if (type.type == JavaType::TypeString || | |
463 type.type == JavaType::TypeObject || | |
464 type.type == JavaType::TypeArray) { | |
465 env->DeleteLocalRef(value->l); | |
466 value->l = NULL; | |
467 } | |
468 } | |
469 | |
470 // Returns a new local reference to a Java array. | |
457 jobject CoerceJavaScriptObjectToArray(const NPVariant& variant, | 471 jobject CoerceJavaScriptObjectToArray(const NPVariant& variant, |
458 const JavaType& target_type) { | 472 const JavaType& target_type) { |
459 DCHECK_EQ(JavaType::TypeArray, target_type.type); | 473 DCHECK_EQ(JavaType::TypeArray, target_type.type); |
460 NPObject* object = NPVARIANT_TO_OBJECT(variant); | 474 NPObject* object = NPVARIANT_TO_OBJECT(variant); |
461 DCHECK_NE(&JavaNPObject::kNPClass, object->_class); | 475 DCHECK_NE(&JavaNPObject::kNPClass, object->_class); |
462 | 476 |
463 const JavaType& target_inner_type = *target_type.inner_type.get(); | 477 const JavaType& target_inner_type = *target_type.inner_type.get(); |
464 // LIVECONNECT_COMPLIANCE: Existing behavior is to return null for | 478 // LIVECONNECT_COMPLIANCE: Existing behavior is to return null for |
465 // multi-dimensional arrays. Spec requires handling multi-demensional arrays. | 479 // multi-dimensional arrays. Spec requires handling multi-demensional arrays. |
466 if (target_inner_type.type == JavaType::TypeArray) { | 480 if (target_inner_type.type == JavaType::TypeArray) { |
(...skipping 24 matching lines...) Expand all Loading... | |
491 } else if (NPVARIANT_IS_DOUBLE(length_variant) | 505 } else if (NPVARIANT_IS_DOUBLE(length_variant) |
492 && NPVARIANT_TO_DOUBLE(length_variant) >= 0.0 | 506 && NPVARIANT_TO_DOUBLE(length_variant) >= 0.0 |
493 && NPVARIANT_TO_DOUBLE(length_variant) <= kint32max) { | 507 && NPVARIANT_TO_DOUBLE(length_variant) <= kint32max) { |
494 length = static_cast<jsize>(NPVARIANT_TO_DOUBLE(length_variant)); | 508 length = static_cast<jsize>(NPVARIANT_TO_DOUBLE(length_variant)); |
495 } | 509 } |
496 WebBindings::releaseVariantValue(&length_variant); | 510 WebBindings::releaseVariantValue(&length_variant); |
497 if (length == -1) { | 511 if (length == -1) { |
498 return NULL; | 512 return NULL; |
499 } | 513 } |
500 | 514 |
501 // Create the Java array. Note that we don't explicitly release the local | 515 // Create the Java array. |
502 // ref to the result or any of its elements. | |
503 // TODO(steveblock): Handle failure to create the array. | 516 // TODO(steveblock): Handle failure to create the array. |
504 jobject result = CreateJavaArray(target_inner_type, length); | 517 jobject result = CreateJavaArray(target_inner_type, length); |
505 NPVariant value_variant; | 518 NPVariant value_variant; |
519 JNIEnv* env = AttachCurrentThread(); | |
506 for (jsize i = 0; i < length; ++i) { | 520 for (jsize i = 0; i < length; ++i) { |
507 // It seems that getProperty() will set the variant to type void on failure, | 521 // 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 | 522 // but this doesn't seem to be documented, so do it explicitly here for |
509 // safety. | 523 // safety. |
510 VOID_TO_NPVARIANT(value_variant); | 524 VOID_TO_NPVARIANT(value_variant); |
511 // If this fails, for example due to a missing element, we simply treat the | 525 // If this fails, for example due to a missing element, we simply treat the |
512 // value as JavaScript undefined. | 526 // value as JavaScript undefined. |
513 WebBindings::getProperty(0, object, WebBindings::getIntIdentifier(i), | 527 WebBindings::getProperty(0, object, WebBindings::getIntIdentifier(i), |
514 &value_variant); | 528 &value_variant); |
515 SetArrayElement(result, target_inner_type, i, | 529 jvalue element = CoerceJavaScriptValueToJavaValue(value_variant, |
516 CoerceJavaScriptValueToJavaValue(value_variant, | 530 target_inner_type, |
517 target_inner_type, | 531 false); |
518 false)); | 532 SetArrayElement(result, target_inner_type, i, element); |
533 // CoerceJavaScriptValueToJavaValue() creates new local references to | |
534 // strings, objects and arrays. Of these, only strings can occur here. | |
535 // SetArrayElement() causes the array to take its own reference to the | |
536 // string, so we can now release the local reference. | |
537 DCHECK_NE(JavaType::TypeObject, target_inner_type.type); | |
538 DCHECK_NE(JavaType::TypeArray, target_inner_type.type); | |
539 ReleaseJavaValueIfRequired(env, &element, target_inner_type); | |
519 WebBindings::releaseVariantValue(&value_variant); | 540 WebBindings::releaseVariantValue(&value_variant); |
520 } | 541 } |
521 | 542 |
522 return result; | 543 return result; |
523 } | 544 } |
524 | 545 |
525 jvalue CoerceJavaScriptObjectToJavaValue(const NPVariant& variant, | 546 jvalue CoerceJavaScriptObjectToJavaValue(const NPVariant& variant, |
526 const JavaType& target_type, | 547 const JavaType& target_type, |
527 bool coerce_to_string) { | 548 bool coerce_to_string) { |
528 // This covers both JavaScript objects (including arrays) and Java objects. | 549 // 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(); | 658 NOTREACHED(); |
638 break; | 659 break; |
639 } | 660 } |
640 return result; | 661 return result; |
641 } | 662 } |
642 | 663 |
643 // coerce_to_string means that we should try to coerce all JavaScript values to | 664 // 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 | 665 // strings when required, rather than simply converting to NULL. This is used |
645 // to maintain current behaviour, which differs slightly depending upon whether | 666 // to maintain current behaviour, which differs slightly depending upon whether |
646 // or not the coercion in question is for an array element. | 667 // or not the coercion in question is for an array element. |
668 // | |
669 // Note that the jvalue returned by this method may contain a new local | |
670 // reference to an object (string, object or array). This must be released by | |
671 // the caller. | |
647 jvalue CoerceJavaScriptValueToJavaValue(const NPVariant& variant, | 672 jvalue CoerceJavaScriptValueToJavaValue(const NPVariant& variant, |
648 const JavaType& target_type, | 673 const JavaType& target_type, |
649 bool coerce_to_string) { | 674 bool coerce_to_string) { |
650 // Note that in all these conversions, the relevant field of the jvalue must | 675 // 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. | 676 // always be explicitly set, as jvalue does not initialize its fields. |
652 | 677 |
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) { | 678 switch (variant.type) { |
657 case NPVariantType_Int32: | 679 case NPVariantType_Int32: |
658 case NPVariantType_Double: | 680 case NPVariantType_Double: |
659 return CoerceJavaScriptNumberToJavaValue(variant, target_type, | 681 return CoerceJavaScriptNumberToJavaValue(variant, target_type, |
660 coerce_to_string); | 682 coerce_to_string); |
661 case NPVariantType_Bool: | 683 case NPVariantType_Bool: |
662 return CoerceJavaScriptBooleanToJavaValue(variant, target_type, | 684 return CoerceJavaScriptBooleanToJavaValue(variant, target_type, |
663 coerce_to_string); | 685 coerce_to_string); |
664 case NPVariantType_String: | 686 case NPVariantType_String: |
665 return CoerceJavaScriptStringToJavaValue(variant, target_type); | 687 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); | 760 std::vector<jvalue> parameters(arg_count); |
739 for (size_t i = 0; i < arg_count; ++i) { | 761 for (size_t i = 0; i < arg_count; ++i) { |
740 parameters[i] = CoerceJavaScriptValueToJavaValue(args[i], | 762 parameters[i] = CoerceJavaScriptValueToJavaValue(args[i], |
741 method->parameter_type(i), | 763 method->parameter_type(i), |
742 true); | 764 true); |
743 } | 765 } |
744 | 766 |
745 // Call | 767 // Call |
746 *result = CallJNIMethod(java_object_.obj(), method->return_type(), | 768 *result = CallJNIMethod(java_object_.obj(), method->return_type(), |
747 method->id(), ¶meters[0]); | 769 method->id(), ¶meters[0]); |
770 | |
771 // Now that we're done with the jvalue, release any local references created | |
772 // by CoerceJavaScriptValueToJavaValue(). | |
773 JNIEnv* env = AttachCurrentThread(); | |
774 for (size_t i = 0; i < arg_count; ++i) { | |
775 ReleaseJavaValueIfRequired(env, ¶meters[i], method->parameter_type(i)); | |
776 } | |
777 | |
748 return true; | 778 return true; |
749 } | 779 } |
750 | 780 |
751 void JavaBoundObject::EnsureMethodsAreSetUp() const { | 781 void JavaBoundObject::EnsureMethodsAreSetUp() const { |
752 if (!methods_.empty()) { | 782 if (!methods_.empty()) { |
753 return; | 783 return; |
754 } | 784 } |
755 | 785 |
756 JNIEnv* env = AttachCurrentThread(); | 786 JNIEnv* env = AttachCurrentThread(); |
757 ScopedJavaLocalRef<jclass> clazz(env, static_cast<jclass>( | 787 ScopedJavaLocalRef<jclass> clazz(env, static_cast<jclass>( |
(...skipping 11 matching lines...) Expand all Loading... | |
769 size_t num_methods = env->GetArrayLength(methods.obj()); | 799 size_t num_methods = env->GetArrayLength(methods.obj()); |
770 DCHECK(num_methods) << "Java objects always have public methods"; | 800 DCHECK(num_methods) << "Java objects always have public methods"; |
771 for (size_t i = 0; i < num_methods; ++i) { | 801 for (size_t i = 0; i < num_methods; ++i) { |
772 ScopedJavaLocalRef<jobject> java_method( | 802 ScopedJavaLocalRef<jobject> java_method( |
773 env, | 803 env, |
774 env->GetObjectArrayElement(methods.obj(), i)); | 804 env->GetObjectArrayElement(methods.obj(), i)); |
775 JavaMethod* method = new JavaMethod(java_method); | 805 JavaMethod* method = new JavaMethod(java_method); |
776 methods_.insert(std::make_pair(method->name(), method)); | 806 methods_.insert(std::make_pair(method->name(), method)); |
777 } | 807 } |
778 } | 808 } |
OLD | NEW |