OSDN Git Service

Merge WebKit at r80534: Fix Java Bridge.
[android-x86/external-webkit.git] / Source / WebCore / bridge / jni / v8 / JNIUtilityPrivate.cpp
1 /*
2  * Copyright 2010, The Android Open Source Project
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *  * Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "JNIUtilityPrivate.h"
28
29 #if ENABLE(JAVA_BRIDGE)
30
31 #include "JavaInstanceV8.h"
32 #include "JavaNPObjectV8.h"
33 #include "npruntime_impl.h"
34 #include <wtf/text/CString.h>
35
36 namespace JSC {
37
38 namespace Bindings {
39
40 jvalue convertNPVariantToJValue(NPVariant value, const WTF::String& javaType)
41 {
42     CString javaClassName = javaType.utf8();
43     JNIType jniType = JNITypeFromClassName(javaClassName.data());
44     jvalue result;
45     NPVariantType type = value.type;
46
47     switch (jniType) {
48     case array_type:
49         {
50             JNIEnv* env = getJNIEnv();
51             jobject javaArray;
52             NPObject* object = NPVARIANT_IS_OBJECT(value) ? NPVARIANT_TO_OBJECT(value) : 0;
53             NPVariant npvLength;
54             bool success = _NPN_GetProperty(0, object, _NPN_GetStringIdentifier("length"), &npvLength);
55             if (!success) {
56                 // No length property so we don't know how many elements to put into the array.
57                 // Treat this as an error.
58 #ifdef EMULATE_JSC_BINDINGS
59                 // JSC sends null for an array that is not an array of strings or basic types,
60                 // do this also in the unknown length case.
61                 memset(&result, 0, sizeof(jvalue));
62 #else
63                 // Sending NULL as JSC does seems dangerous. (Imagine the java method that asks
64                 // for the length of the array it was passed). Here we send a 0 length array.
65                 jclass objectClass = env->FindClass("java/lang/Object");
66                 javaArray = env->NewObjectArray(0, objectClass, 0);
67                 env->DeleteLocalRef(objectClass);
68 #endif
69                 break;
70             }
71
72             jsize length = 0;
73             if (NPVARIANT_IS_INT32(npvLength))
74                 length = static_cast<jsize>(NPVARIANT_TO_INT32(npvLength));
75             else if (NPVARIANT_IS_DOUBLE(npvLength))
76                 length = static_cast<jsize>(NPVARIANT_TO_DOUBLE(npvLength));
77
78             if (!strcmp(javaClassName.data(), "[Ljava.lang.String;")) {
79                 // Match JSC behavior by only allowing Object arrays if they are Strings.
80                 jclass stringClass = env->FindClass("java/lang/String");
81                 javaArray = env->NewObjectArray(length, stringClass, 0);
82                 for (jsize i = 0; i < length; i++) {
83                     NPVariant npvValue;
84                     _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
85                     if(NPVARIANT_IS_STRING(npvValue)) {
86                         NPString str = NPVARIANT_TO_STRING(npvValue);
87                         env->SetObjectArrayElement(static_cast<jobjectArray>(javaArray), i, env->NewStringUTF(str.UTF8Characters));
88                     }
89                 }
90
91                 env->DeleteLocalRef(stringClass);
92             } else if (!strcmp(javaClassName.data(), "[B")) {
93                 // array of bytes
94                 javaArray = env->NewByteArray(length);
95                 // Now iterate over each element and add to the array.
96                 for (jsize i = 0; i < length; i++) {
97                     NPVariant npvValue;
98                     _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
99                     jbyte bVal = 0;
100                     if (NPVARIANT_IS_INT32(npvValue)) {
101                         bVal = static_cast<jbyte>(NPVARIANT_TO_INT32(npvValue));
102                     } else if (NPVARIANT_IS_DOUBLE(npvValue)) {
103                         bVal = static_cast<jbyte>(NPVARIANT_TO_DOUBLE(npvValue));
104                     }
105                     env->SetByteArrayRegion(static_cast<jbyteArray>(javaArray), i, 1, &bVal);
106                 }
107              } else if (!strcmp(javaClassName.data(), "[C")) {
108                 // array of chars
109                 javaArray = env->NewCharArray(length);
110                 // Now iterate over each element and add to the array.
111                 for (jsize i = 0; i < length; i++) {
112                     NPVariant npvValue;
113                     _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
114                     jchar cVal = 0;
115                     if (NPVARIANT_IS_INT32(npvValue)) {
116                         cVal = static_cast<jchar>(NPVARIANT_TO_INT32(npvValue));
117                     } else if (NPVARIANT_IS_STRING(npvValue)) {
118                         NPString str = NPVARIANT_TO_STRING(npvValue);
119                         cVal = str.UTF8Characters[0];
120                     }
121                     env->SetCharArrayRegion(static_cast<jcharArray>(javaArray), i, 1, &cVal);
122                 }
123              } else if (!strcmp(javaClassName.data(), "[D")) {
124                 // array of doubles
125                 javaArray = env->NewDoubleArray(length);
126                 // Now iterate over each element and add to the array.
127                 for (jsize i = 0; i < length; i++) {
128                     NPVariant npvValue;
129                     _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
130                     if (NPVARIANT_IS_DOUBLE(npvValue)) {
131                         jdouble dVal = NPVARIANT_TO_DOUBLE(npvValue);
132                         env->SetDoubleArrayRegion(static_cast<jdoubleArray>(javaArray), i, 1, &dVal);
133                     }
134                 }
135              } else if (!strcmp(javaClassName.data(), "[F")) {
136                 // array of floats
137                 javaArray = env->NewFloatArray(length);
138                 // Now iterate over each element and add to the array.
139                 for (jsize i = 0; i < length; i++) {
140                     NPVariant npvValue;
141                     _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
142                     if (NPVARIANT_IS_DOUBLE(npvValue)) {
143                         jfloat fVal = static_cast<jfloat>(NPVARIANT_TO_DOUBLE(npvValue));
144                         env->SetFloatArrayRegion(static_cast<jfloatArray>(javaArray), i, 1, &fVal);
145                     }
146                 }
147              } else if (!strcmp(javaClassName.data(), "[I")) {
148                 // array of ints
149                 javaArray = env->NewIntArray(length);
150                 // Now iterate over each element and add to the array.
151                 for (jsize i = 0; i < length; i++) {
152                     NPVariant npvValue;
153                     _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
154                     jint iVal = 0;
155                     if (NPVARIANT_IS_INT32(npvValue)) {
156                         iVal = NPVARIANT_TO_INT32(npvValue);
157                     } else if (NPVARIANT_IS_DOUBLE(npvValue)) {
158                         iVal = static_cast<jint>(NPVARIANT_TO_DOUBLE(npvValue));
159                     }
160                     env->SetIntArrayRegion(static_cast<jintArray>(javaArray), i, 1, &iVal);
161                 }
162              } else if (!strcmp(javaClassName.data(), "[J")) {
163                 // array of longs
164                 javaArray = env->NewLongArray(length);
165                 // Now iterate over each element and add to the array.
166                 for (jsize i = 0; i < length; i++) {
167                     NPVariant npvValue;
168                     _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
169                     jlong jVal = 0;
170                     if (NPVARIANT_IS_INT32(npvValue)) {
171                         jVal = static_cast<jlong>(NPVARIANT_TO_INT32(npvValue));
172                     } else if (NPVARIANT_IS_DOUBLE(npvValue)) {
173                         jVal = static_cast<jlong>(NPVARIANT_TO_DOUBLE(npvValue));
174                     }
175                     env->SetLongArrayRegion(static_cast<jlongArray>(javaArray), i, 1, &jVal);
176                 }
177              } else if (!strcmp(javaClassName.data(), "[S")) {
178                 // array of shorts
179                 javaArray = env->NewShortArray(length);
180                 // Now iterate over each element and add to the array.
181                 for (jsize i = 0; i < length; i++) {
182                     NPVariant npvValue;
183                     _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
184                     jshort sVal = 0;
185                     if (NPVARIANT_IS_INT32(npvValue)) {
186                         sVal = static_cast<jshort>(NPVARIANT_TO_INT32(npvValue));
187                     } else if (NPVARIANT_IS_DOUBLE(npvValue)) {
188                         sVal = static_cast<jshort>(NPVARIANT_TO_DOUBLE(npvValue));
189                     }
190                     env->SetShortArrayRegion(static_cast<jshortArray>(javaArray), i, 1, &sVal);
191                 }
192              } else if (!strcmp(javaClassName.data(), "[Z")) {
193                 // array of booleans
194                 javaArray = env->NewBooleanArray(length);
195                 // Now iterate over each element and add to the array.
196                 for (jsize i = 0; i < length; i++) {
197                     NPVariant npvValue;
198                     _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
199                     if (NPVARIANT_IS_BOOLEAN(npvValue)) {
200                         jboolean zVal = NPVARIANT_TO_BOOLEAN(npvValue);
201                         env->SetBooleanArrayRegion(static_cast<jbooleanArray>(javaArray), i, 1, &zVal);
202                     }
203                 }
204             } else {
205 #ifdef EMULATE_JSC_BINDINGS
206                 // JSC sends null for an array that is not an array of strings or basic types.
207                 memset(&result, 0, sizeof(jvalue));
208                 break;
209 #else
210                 // Sending NULL as JSC does seems dangerous. (Imagine the java method that asks
211                 // for the length of the array it was passed). Here we send a 0 length array.
212                 jclass objectClass = env->FindClass("java/lang/Object");
213                 javaArray = env->NewObjectArray(0, objectClass, 0);
214                 env->DeleteLocalRef(objectClass);
215 #endif
216             }
217
218             result.l = javaArray;
219         }
220         break;
221
222     case object_type:
223         {
224             JNIEnv* env = getJNIEnv();
225             result.l = static_cast<jobject>(0);
226             jobject javaString;
227
228             // First see if we have a Java instance.
229             if (type == NPVariantType_Object) {
230                 NPObject* objectImp = NPVARIANT_TO_OBJECT(value);
231                 if (JavaInstance* instance = ExtractJavaInstance(objectImp))
232                     result.l = instance->javaInstance();
233             }
234
235             // Now convert value to a string if the target type is a java.lang.string, and we're not
236             // converting from a Null.
237             if (!result.l && !strcmp(javaClassName.data(), "java.lang.String")) {
238 #ifdef CONVERT_NULL_TO_EMPTY_STRING
239                 if (type == NPVariantType_Null) {
240                     jchar buf[2];
241                     jobject javaString = env->functions->NewString(env, buf, 0);
242                     result.l = javaString;
243                 } else
244 #else
245                 if (type == NPVariantType_String)
246 #endif
247                 {
248                     NPString src = NPVARIANT_TO_STRING(value);
249                     javaString = env->NewStringUTF(src.UTF8Characters);
250                     result.l = javaString;
251                 } else if (type == NPVariantType_Int32) {
252                     jint src = NPVARIANT_TO_INT32(value);
253                     jclass integerClass = env->FindClass("java/lang/Integer");
254                     jmethodID toString = env->GetStaticMethodID(integerClass, "toString", "(I)Ljava/lang/String;");
255                     javaString = env->CallStaticObjectMethod(integerClass, toString, src);
256                     result.l = javaString;
257                     env->DeleteLocalRef(integerClass);
258                 } else if (type == NPVariantType_Bool) {
259                     jboolean src = NPVARIANT_TO_BOOLEAN(value);
260                     jclass booleanClass = env->FindClass("java/lang/Boolean");
261                     jmethodID toString = env->GetStaticMethodID(booleanClass, "toString", "(Z)Ljava/lang/String;");
262                     javaString = env->CallStaticObjectMethod(booleanClass, toString, src);
263                     result.l = javaString;
264                     env->DeleteLocalRef(booleanClass);
265                 } else if (type == NPVariantType_Double) {
266                     jdouble src = NPVARIANT_TO_DOUBLE(value);
267                     jclass doubleClass = env->FindClass("java/lang/Double");
268                     jmethodID toString = env->GetStaticMethodID(doubleClass, "toString", "(D)Ljava/lang/String;");
269                     javaString = env->CallStaticObjectMethod(doubleClass, toString, src);
270                     result.l = javaString;
271                     env->DeleteLocalRef(doubleClass);
272                 }
273 #ifdef EMULATE_JSC_BINDINGS
274                 // For the undefined value, JSC sends the String "undefined". Feels to me like we
275                 // should send null in this case.
276                 else if (!NPVARIANT_IS_NULL(value)) {
277                   javaString = env->NewStringUTF("undefined");
278                   result.l = javaString;
279                 }
280 #endif
281             } else if (!result.l)
282                 memset(&result, 0, sizeof(jvalue)); // Handle it the same as a void case
283         }
284         break;
285
286     case boolean_type:
287         {
288             if (type == NPVariantType_Bool)
289                 result.z = NPVARIANT_TO_BOOLEAN(value);
290             else
291                 memset(&result, 0, sizeof(jvalue)); // as void case
292         }
293         break;
294
295     case byte_type:
296         {
297             if (type == NPVariantType_Int32)
298                 result.b = static_cast<jbyte>(NPVARIANT_TO_INT32(value));
299             else if (type == NPVariantType_Double)
300                 result.b = static_cast<jbyte>(NPVARIANT_TO_DOUBLE(value));
301             else
302                 memset(&result, 0, sizeof(jvalue));
303         }
304         break;
305
306     case char_type:
307         {
308             if (type == NPVariantType_Int32)
309                 result.c = static_cast<char>(NPVARIANT_TO_INT32(value));
310 #ifndef EMULATE_JSC_BINDINGS
311             // There is no char type in JavaScript - just strings 1 character
312             // long. So just converting it to an int above doesn't work. Again,
313             // we emulate the behavior for now for maximum compatability.
314             else if (type == NPVariantType_String) {
315                 NPString str = NPVARIANT_TO_STRING(value);
316                 result.c = str.UTF8Characters[0];
317             }
318 #endif
319             else
320                 memset(&result, 0, sizeof(jvalue));
321         }
322         break;
323
324     case short_type:
325         {
326             if (type == NPVariantType_Int32)
327                 result.s = static_cast<jshort>(NPVARIANT_TO_INT32(value));
328             else if (type == NPVariantType_Double)
329                 result.s = static_cast<jshort>(NPVARIANT_TO_DOUBLE(value));
330             else
331                 memset(&result, 0, sizeof(jvalue));
332         }
333         break;
334
335     case int_type:
336         {
337             if (type == NPVariantType_Int32)
338                 result.i = static_cast<jint>(NPVARIANT_TO_INT32(value));
339             else if (type == NPVariantType_Double)
340                 result.i = static_cast<jint>(NPVARIANT_TO_DOUBLE(value));
341             else
342                 memset(&result, 0, sizeof(jvalue));
343         }
344         break;
345
346     case long_type:
347         {
348             if (type == NPVariantType_Int32)
349                 result.j = static_cast<jlong>(NPVARIANT_TO_INT32(value));
350             else if (type == NPVariantType_Double)
351                 result.j = static_cast<jlong>(NPVARIANT_TO_DOUBLE(value));
352             else
353                 memset(&result, 0, sizeof(jvalue));
354         }
355         break;
356
357     case float_type:
358         {
359             if (type == NPVariantType_Int32)
360                 result.f = static_cast<jfloat>(NPVARIANT_TO_INT32(value));
361             else if (type == NPVariantType_Double)
362                 result.f = static_cast<jfloat>(NPVARIANT_TO_DOUBLE(value));
363             else
364                 memset(&result, 0, sizeof(jvalue));
365         }
366         break;
367
368     case double_type:
369         {
370             if (type == NPVariantType_Int32)
371                 result.d = static_cast<jdouble>(NPVARIANT_TO_INT32(value));
372             else if (type == NPVariantType_Double)
373                 result.d = static_cast<jdouble>(NPVARIANT_TO_DOUBLE(value));
374             else
375                 memset(&result, 0, sizeof(jvalue));
376         }
377         break;
378
379     case invalid_type:
380     default:
381     case void_type:
382         {
383             memset(&result, 0, sizeof(jvalue));
384         }
385         break;
386     }
387     return result;
388 }
389
390
391 void convertJValueToNPVariant(jvalue value, JNIType jniType, const char* javaTypeName, NPVariant* result)
392 {
393     switch (jniType) {
394     case void_type:
395         {
396             VOID_TO_NPVARIANT(*result);
397         }
398         break;
399
400     case object_type:
401         {
402             if (value.l) {
403                 if (!strcmp(javaTypeName, "java.lang.String")) {
404                     const char* v = getCharactersFromJString(static_cast<jstring>(value.l));
405                     // s is freed in NPN_ReleaseVariantValue (see npruntime.cpp)
406                     const char* s = strdup(v);
407                     releaseCharactersForJString(static_cast<jstring>(value.l), v);
408                     STRINGZ_TO_NPVARIANT(s, *result);
409                 } else
410                     OBJECT_TO_NPVARIANT(JavaInstanceToNPObject(new JavaInstance(value.l)), *result);
411             } else
412                 VOID_TO_NPVARIANT(*result);
413         }
414         break;
415
416     case boolean_type:
417         {
418             BOOLEAN_TO_NPVARIANT(value.z, *result);
419         }
420         break;
421
422     case byte_type:
423         {
424             INT32_TO_NPVARIANT(value.b, *result);
425         }
426         break;
427
428     case char_type:
429         {
430 #ifndef EMULATE_JSC_BINDINGS
431             // There is no char type in JavaScript - just strings 1 character
432             // long. So just converting it to an int above doesn't work. Again,
433             // we emulate the behavior for now for maximum compatability.
434             if (!strcmp(javaTypeName, "char")) {
435                 const char c = value.c;
436                 const char* v = strndup(&c, 1);
437                 STRINGZ_TO_NPVARIANT(v, *result);
438             } else
439 #endif
440                 INT32_TO_NPVARIANT(value.c, *result);
441         }
442         break;
443
444     case short_type:
445         {
446             INT32_TO_NPVARIANT(value.s, *result);
447         }
448         break;
449
450     case int_type:
451         {
452             INT32_TO_NPVARIANT(value.i, *result);
453         }
454         break;
455
456         // TODO: Check if cast to double is needed.
457     case long_type:
458         {
459             DOUBLE_TO_NPVARIANT(value.j, *result);
460         }
461         break;
462
463     case float_type:
464         {
465             DOUBLE_TO_NPVARIANT(value.f, *result);
466         }
467         break;
468
469     case double_type:
470         {
471             DOUBLE_TO_NPVARIANT(value.d, *result);
472         }
473         break;
474
475     case invalid_type:
476     default:
477         {
478             VOID_TO_NPVARIANT(*result);
479         }
480         break;
481     }
482 }
483
484 } // namespace Bindings
485
486 } // namespace JSC
487
488 #endif // ENABLE(JAVA_BRIDGE)