Move WebCore into Source
[WebKit-https.git] / Source / WebCore / bridge / jni / jsc / JNIBridgeJSC.cpp
1 /*
2  * Copyright (C) 2003, 2004, 2005, 2007, 2009 Apple Inc. All rights reserved.
3  * Copyright 2010, The Android Open Source Project
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "JNIBridgeJSC.h"
29
30 #if ENABLE(JAVA_BRIDGE)
31
32 #include "JNIUtilityPrivate.h"
33 #include "Logging.h"
34 #include "runtime_array.h"
35 #include "runtime_object.h"
36 #include <runtime/Error.h>
37
38 using namespace JSC;
39 using namespace JSC::Bindings;
40 using namespace WebCore;
41
42 JavaField::JavaField(JNIEnv* env, jobject aField)
43 {
44     // Get field type name
45     jstring fieldTypeName = 0;
46     if (jobject fieldType = callJNIMethod<jobject>(aField, "getType", "()Ljava/lang/Class;"))
47         fieldTypeName = static_cast<jstring>(callJNIMethod<jobject>(fieldType, "getName", "()Ljava/lang/String;"));
48     if (!fieldTypeName)
49         fieldTypeName = env->NewStringUTF("<Unknown>");
50     m_type = JavaString(env, fieldTypeName);
51
52     m_JNIType = JNITypeFromClassName(m_type.utf8());
53
54     // Get field name
55     jstring fieldName = static_cast<jstring>(callJNIMethod<jobject>(aField, "getName", "()Ljava/lang/String;"));
56     if (!fieldName)
57         fieldName = env->NewStringUTF("<Unknown>");
58     m_name = JavaString(env, fieldName);
59
60     m_field = new JObjectWrapper(aField);
61 }
62
63 JSValue JavaArray::convertJObjectToArray(ExecState* exec, jobject anObject, const char* type, PassRefPtr<RootObject> rootObject)
64 {
65     if (type[0] != '[')
66         return jsUndefined();
67
68     return new (exec) RuntimeArray(exec, new JavaArray(anObject, type, rootObject));
69 }
70
71 jvalue JavaField::dispatchValueFromInstance(ExecState* exec, const JavaInstance* instance, const char* name, const char* sig, JNIType returnType) const
72 {
73     jobject jinstance = instance->javaInstance();
74     jobject fieldJInstance = m_field->m_instance;
75     JNIEnv* env = getJNIEnv();
76     jvalue result;
77
78     memset(&result, 0, sizeof(jvalue));
79     jclass cls = env->GetObjectClass(fieldJInstance);
80     if (cls) {
81         jmethodID mid = env->GetMethodID(cls, name, sig);
82         if (mid) {
83             RootObject* rootObject = instance->rootObject();
84             if (rootObject && rootObject->nativeHandle()) {
85                 JSValue exceptionDescription;
86                 jvalue args[1];
87
88                 args[0].l = jinstance;
89                 dispatchJNICall(exec, rootObject->nativeHandle(), fieldJInstance, false, returnType, mid, args, result, 0, exceptionDescription);
90                 if (exceptionDescription)
91                     throwError(exec, createError(exec, exceptionDescription.toString(exec)));
92             }
93         }
94     }
95     return result;
96 }
97
98 JSValue JavaField::valueFromInstance(ExecState* exec, const Instance* i) const
99 {
100     const JavaInstance* instance = static_cast<const JavaInstance*>(i);
101
102     JSValue jsresult = jsUndefined();
103
104     switch (m_JNIType) {
105     case array_type:
106     case object_type:
107         {
108             jvalue result = dispatchValueFromInstance(exec, instance, "get", "(Ljava/lang/Object;)Ljava/lang/Object;", object_type);
109             jobject anObject = result.l;
110
111             if (!anObject)
112                 return jsNull();
113
114             const char* arrayType = type();
115             if (arrayType[0] == '[')
116                 jsresult = JavaArray::convertJObjectToArray(exec, anObject, arrayType, instance->rootObject());
117             else if (anObject)
118                 jsresult = JavaInstance::create(anObject, instance->rootObject())->createRuntimeObject(exec);
119         }
120         break;
121
122     case boolean_type:
123         jsresult = jsBoolean(dispatchValueFromInstance(exec, instance, "getBoolean", "(Ljava/lang/Object;)Z", boolean_type).z);
124         break;
125
126     case byte_type:
127     case char_type:
128     case short_type:
129
130     case int_type:
131         {
132             jint value;
133             jvalue result = dispatchValueFromInstance(exec, instance, "getInt", "(Ljava/lang/Object;)I", int_type);
134             value = result.i;
135             jsresult = jsNumber(static_cast<int>(value));
136         }
137         break;
138
139     case long_type:
140     case float_type:
141     case double_type:
142         {
143             jdouble value;
144             jvalue result = dispatchValueFromInstance(exec, instance, "getDouble", "(Ljava/lang/Object;)D", double_type);
145             value = result.i;
146             jsresult = jsNumber(static_cast<double>(value));
147         }
148         break;
149     default:
150         break;
151     }
152
153     LOG(LiveConnect, "JavaField::valueFromInstance getting %s = %s", UString(name()).utf8().data(), jsresult.toString(exec).ascii().data());
154
155     return jsresult;
156 }
157
158 void JavaField::dispatchSetValueToInstance(ExecState* exec, const JavaInstance* instance, jvalue javaValue, const char* name, const char* sig) const
159 {
160     jobject jinstance = instance->javaInstance();
161     jobject fieldJInstance = m_field->m_instance;
162     JNIEnv* env = getJNIEnv();
163
164     jclass cls = env->GetObjectClass(fieldJInstance);
165     if (cls) {
166         jmethodID mid = env->GetMethodID(cls, name, sig);
167         if (mid) {
168             RootObject* rootObject = instance->rootObject();
169             if (rootObject && rootObject->nativeHandle()) {
170                 JSValue exceptionDescription;
171                 jvalue args[2];
172                 jvalue result;
173
174                 args[0].l = jinstance;
175                 args[1] = javaValue;
176                 dispatchJNICall(exec, rootObject->nativeHandle(), fieldJInstance, false, void_type, mid, args, result, 0, exceptionDescription);
177                 if (exceptionDescription)
178                     throwError(exec, createError(exec, exceptionDescription.toString(exec)));
179             }
180         }
181     }
182 }
183
184 void JavaField::setValueToInstance(ExecState* exec, const Instance* i, JSValue aValue) const
185 {
186     const JavaInstance* instance = static_cast<const JavaInstance*>(i);
187     jvalue javaValue = convertValueToJValue(exec, i->rootObject(), aValue, m_JNIType, type());
188
189     LOG(LiveConnect, "JavaField::setValueToInstance setting value %s to %s", UString(name()).utf8().data(), aValue.toString(exec).ascii().data());
190
191     switch (m_JNIType) {
192     case array_type:
193     case object_type:
194         {
195             dispatchSetValueToInstance(exec, instance, javaValue, "set", "(Ljava/lang/Object;Ljava/lang/Object;)V");
196         }
197         break;
198
199     case boolean_type:
200         {
201             dispatchSetValueToInstance(exec, instance, javaValue, "setBoolean", "(Ljava/lang/Object;Z)V");
202         }
203         break;
204
205     case byte_type:
206         {
207             dispatchSetValueToInstance(exec, instance, javaValue, "setByte", "(Ljava/lang/Object;B)V");
208         }
209         break;
210
211     case char_type:
212         {
213             dispatchSetValueToInstance(exec, instance, javaValue, "setChar", "(Ljava/lang/Object;C)V");
214         }
215         break;
216
217     case short_type:
218         {
219             dispatchSetValueToInstance(exec, instance, javaValue, "setShort", "(Ljava/lang/Object;S)V");
220         }
221         break;
222
223     case int_type:
224         {
225             dispatchSetValueToInstance(exec, instance, javaValue, "setInt", "(Ljava/lang/Object;I)V");
226         }
227         break;
228
229     case long_type:
230         {
231             dispatchSetValueToInstance(exec, instance, javaValue, "setLong", "(Ljava/lang/Object;J)V");
232         }
233         break;
234
235     case float_type:
236         {
237             dispatchSetValueToInstance(exec, instance, javaValue, "setFloat", "(Ljava/lang/Object;F)V");
238         }
239         break;
240
241     case double_type:
242         {
243             dispatchSetValueToInstance(exec, instance, javaValue, "setDouble", "(Ljava/lang/Object;D)V");
244         }
245         break;
246     default:
247         break;
248     }
249 }
250
251 JavaArray::JavaArray(jobject array, const char* type, PassRefPtr<RootObject> rootObject)
252     : Array(rootObject)
253 {
254     m_array = new JObjectWrapper(array);
255     // Java array are fixed length, so we can cache length.
256     JNIEnv* env = getJNIEnv();
257     m_length = env->GetArrayLength(static_cast<jarray>(m_array->m_instance));
258     m_type = strdup(type);
259 }
260
261 JavaArray::~JavaArray()
262 {
263     free(const_cast<char*>(m_type));
264 }
265
266 RootObject* JavaArray::rootObject() const
267 {
268     return m_rootObject && m_rootObject->isValid() ? m_rootObject.get() : 0;
269 }
270
271 void JavaArray::setValueAt(ExecState* exec, unsigned index, JSValue aValue) const
272 {
273     JNIEnv* env = getJNIEnv();
274     char* javaClassName = 0;
275
276     JNIType arrayType = JNITypeFromPrimitiveType(m_type[1]);
277     if (m_type[1] == 'L') {
278         // The type of the array will be something like:
279         // "[Ljava.lang.string;".  This is guaranteed, so no need
280         // for extra sanity checks.
281         javaClassName = strdup(&m_type[2]);
282         javaClassName[strchr(javaClassName, ';')-javaClassName] = 0;
283     }
284     jvalue aJValue = convertValueToJValue(exec, m_rootObject.get(), aValue, arrayType, javaClassName);
285
286     switch (arrayType) {
287     case object_type:
288         {
289             env->SetObjectArrayElement(static_cast<jobjectArray>(javaArray()), index, aJValue.l);
290             break;
291         }
292
293     case boolean_type:
294         {
295             env->SetBooleanArrayRegion(static_cast<jbooleanArray>(javaArray()), index, 1, &aJValue.z);
296             break;
297         }
298
299     case byte_type:
300         {
301             env->SetByteArrayRegion(static_cast<jbyteArray>(javaArray()), index, 1, &aJValue.b);
302             break;
303         }
304
305     case char_type:
306         {
307             env->SetCharArrayRegion(static_cast<jcharArray>(javaArray()), index, 1, &aJValue.c);
308             break;
309         }
310
311     case short_type:
312         {
313             env->SetShortArrayRegion(static_cast<jshortArray>(javaArray()), index, 1, &aJValue.s);
314             break;
315         }
316
317     case int_type:
318         {
319             env->SetIntArrayRegion(static_cast<jintArray>(javaArray()), index, 1, &aJValue.i);
320             break;
321         }
322
323     case long_type:
324         {
325             env->SetLongArrayRegion(static_cast<jlongArray>(javaArray()), index, 1, &aJValue.j);
326         }
327
328     case float_type:
329         {
330             env->SetFloatArrayRegion(static_cast<jfloatArray>(javaArray()), index, 1, &aJValue.f);
331             break;
332         }
333
334     case double_type:
335         {
336             env->SetDoubleArrayRegion(static_cast<jdoubleArray>(javaArray()), index, 1, &aJValue.d);
337             break;
338         }
339     default:
340         break;
341     }
342
343     if (javaClassName)
344         free(const_cast<char*>(javaClassName));
345 }
346
347
348 JSValue JavaArray::valueAt(ExecState* exec, unsigned index) const
349 {
350     JNIEnv* env = getJNIEnv();
351     JNIType arrayType = JNITypeFromPrimitiveType(m_type[1]);
352     switch (arrayType) {
353     case object_type:
354         {
355             jobjectArray objectArray = static_cast<jobjectArray>(javaArray());
356             jobject anObject;
357             anObject = env->GetObjectArrayElement(objectArray, index);
358
359             // No object?
360             if (!anObject)
361                 return jsNull();
362
363             // Nested array?
364             if (m_type[1] == '[')
365                 return JavaArray::convertJObjectToArray(exec, anObject, m_type + 1, rootObject());
366             // or array of other object type?
367             return JavaInstance::create(anObject, rootObject())->createRuntimeObject(exec);
368         }
369
370     case boolean_type:
371         {
372             jbooleanArray booleanArray = static_cast<jbooleanArray>(javaArray());
373             jboolean aBoolean;
374             env->GetBooleanArrayRegion(booleanArray, index, 1, &aBoolean);
375             return jsBoolean(aBoolean);
376         }
377
378     case byte_type:
379         {
380             jbyteArray byteArray = static_cast<jbyteArray>(javaArray());
381             jbyte aByte;
382             env->GetByteArrayRegion(byteArray, index, 1, &aByte);
383             return jsNumber(aByte);
384         }
385
386     case char_type:
387         {
388             jcharArray charArray = static_cast<jcharArray>(javaArray());
389             jchar aChar;
390             env->GetCharArrayRegion(charArray, index, 1, &aChar);
391             return jsNumber(aChar);
392             break;
393         }
394
395     case short_type:
396         {
397             jshortArray shortArray = static_cast<jshortArray>(javaArray());
398             jshort aShort;
399             env->GetShortArrayRegion(shortArray, index, 1, &aShort);
400             return jsNumber(aShort);
401         }
402
403     case int_type:
404         {
405             jintArray intArray = static_cast<jintArray>(javaArray());
406             jint anInt;
407             env->GetIntArrayRegion(intArray, index, 1, &anInt);
408             return jsNumber(anInt);
409         }
410
411     case long_type:
412         {
413             jlongArray longArray = static_cast<jlongArray>(javaArray());
414             jlong aLong;
415             env->GetLongArrayRegion(longArray, index, 1, &aLong);
416             return jsNumber(aLong);
417         }
418
419     case float_type:
420         {
421             jfloatArray floatArray = static_cast<jfloatArray>(javaArray());
422             jfloat aFloat;
423             env->GetFloatArrayRegion(floatArray, index, 1, &aFloat);
424             return jsNumber(aFloat);
425         }
426
427     case double_type:
428         {
429             jdoubleArray doubleArray = static_cast<jdoubleArray>(javaArray());
430             jdouble aDouble;
431             env->GetDoubleArrayRegion(doubleArray, index, 1, &aDouble);
432             return jsNumber(aDouble);
433         }
434     default:
435         break;
436     }
437     return jsUndefined();
438 }
439
440 unsigned int JavaArray::getLength() const
441 {
442     return m_length;
443 }
444
445 #endif // ENABLE(JAVA_BRIDGE)