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