Reviewed by Eric.
[WebKit-https.git] / JavaScriptGlue / JavaScriptGlue.cpp
1 /*
2     JSGlue.cpp
3 */
4
5 #include "JavaScriptGlue.h"
6 #include "JSUtils.h"
7 #include "JSBase.h"
8 #include "JSObject.h"
9 #include "JSRun.h"
10
11 static CFTypeRef sJSCFNullRef = 0;
12
13 static void CFJSObjectDispose(void *data);
14 static JSObjectRef CFJSObjectCopyProperty(void *data, CFStringRef propertyName);
15 static void CFJSObjectSetProperty(void *data, CFStringRef propertyName, JSObjectRef jsValue);
16 static CFTypeRef CFJSObjectCopyCFValue(void *data);
17 static UInt8 CFJSObjectEqual(void *data1, void *data2);
18 static CFArrayRef CFJSObjectCopyPropertyNames(void *data);
19
20 void *JSCFRetain(CFAllocatorRef allocator, const void *value);
21 void JSCFRelease(CFAllocatorRef allocator, const void *value);
22
23
24 void JSSetCFNull(CFTypeRef nullRef)
25 {
26     ReleaseCFType(sJSCFNullRef);
27     sJSCFNullRef = RetainCFType(nullRef);
28 }
29
30 CFTypeRef JSGetCFNull(void)
31 {
32     return sJSCFNullRef;
33 }
34
35 /*
36     JSRetain
37 */
38 JSTypeRef JSRetain(JSTypeRef ref)
39 {
40     if (ref)
41     {
42         JSBase* ptr = (JSBase*)ref;
43         ptr->Retain();
44     }
45     return ref;
46 }
47
48 /*
49     JSRelease
50 */
51 void JSRelease(JSTypeRef ref)
52 {
53     if (ref)
54     {
55         JSBase* ptr = (JSBase*)ref;
56         ptr->Release();
57     }
58 }
59
60 /*
61     JSCopyDescription
62 */
63 CFStringRef JSCopyDescription(JSTypeRef ref)
64 {
65     CFStringRef result = 0;
66     if (ref)
67     {
68         JSBase* ptr = (JSBase*)ref;
69         ptr->CopyDescription();
70     }
71     return result;
72 }
73
74 /*
75     JSEqual
76 */
77 UInt8 JSEqual(JSTypeRef ref1, JSTypeRef ref2)
78 {
79     UInt8 result = false;
80     if (ref1 && ref2)
81     {
82         JSBase* ptr = (JSBase*)ref1;
83         result = ptr->Equal((JSBase*)ref2);
84     }
85     return result;
86 }
87
88
89 /*
90     JSGetTypeID
91 */
92 JSTypeID JSGetTypeID(JSTypeRef ref)
93 {
94     JSTypeID result = kJSInvalidTypeID;
95     if (ref)
96     {
97         JSBase* ptr = (JSBase*)ref;
98         result = ptr->GetTypeID();
99     }
100     return result;
101 }
102
103
104 /*
105     JSGetRetainCount
106 */
107 CFIndex JSGetRetainCount(JSTypeRef ref)
108 {
109     CFIndex result = -1;
110     if (ref)
111     {
112         JSBase* ptr = (JSBase*)ref;
113         result = ptr->RetainCount();
114     }
115     return result;
116 }
117
118
119
120 /*
121     JSObjectCreate
122 */
123 JSObjectRef JSObjectCreate(void *data, JSObjectCallBacksPtr callBacks)
124 {
125     JSObjectRef result = JSObjectCreateInternal(data, callBacks, 0, kJSUserObjectDataTypeUnknown);
126     return result;
127 }
128
129 /*
130     JSObjectCreateInternal
131 */
132 JSObjectRef JSObjectCreateInternal(void *data, JSObjectCallBacksPtr callBacks, JSObjectMarkProcPtr markProc, int type)
133 {
134     JSObjectRef result = 0;
135     JSUserObject* ptr = new JSUserObject(callBacks, markProc, data, type);
136     result = (JSObjectRef)ptr;
137     return result;
138 }
139
140 /*
141     JSObjectCopyCFValue
142 */
143 CFTypeRef JSObjectCopyCFValue(JSObjectRef ref)
144 {
145     CFTypeRef result = 0;
146     JSUserObject* ptr = (JSUserObject*)ref;
147     if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
148     {
149         result = ptr->CopyCFValue();
150     }
151     return result;
152 }
153
154 /*
155     JSObjectGetData
156 */
157 void *JSObjectGetData(JSObjectRef ref)
158 {
159     void *result = 0;
160     JSUserObject* ptr = (JSUserObject*)ref;
161     if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
162     {
163         result = ptr->GetData();
164     }
165     return result;
166 }
167
168
169 /*
170     JSObjectCopyProperty
171 */
172 JSObjectRef JSObjectCopyProperty(JSObjectRef ref, CFStringRef propertyName)
173 {
174     JSObjectRef result = 0;
175     JSUserObject* ptr = (JSUserObject*)ref;
176     if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
177     {
178         result = (JSObjectRef)ptr->CopyProperty(propertyName);
179     }
180     return result;
181 }
182
183
184 /*
185     JSObjectSetProperty
186 */
187 void JSObjectSetProperty(JSObjectRef ref, CFStringRef propertyName, JSObjectRef value)
188 {
189     JSUserObject* ptr = (JSUserObject*)ref;
190     if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
191     {
192         ptr->SetProperty(propertyName, (JSUserObject*)value);
193     }
194 }
195
196
197 /*
198     JSObjectCallFunction
199 */
200 JSObjectRef JSObjectCallFunction(JSObjectRef ref, JSObjectRef thisObj, CFArrayRef args)
201 {
202     JSObjectRef result = 0;
203     JSUserObject* ptr = (JSUserObject*)ref;
204     if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
205     {
206         result = (JSObjectRef)ptr->CallFunction((JSUserObject*)thisObj, args);
207     }
208     return result;
209 }
210
211
212 /*
213     JSRunCreate
214 */
215 JSRunRef JSRunCreate(CFStringRef jsSource, JSFlags inFlags)
216 {
217     JSRunRef result = 0;
218     if (jsSource)
219     {
220         result = (JSRunRef) new JSRun(jsSource, inFlags);
221     }
222     return result;
223 }
224
225 /*
226     JSRunCopySource
227 */
228 CFStringRef JSRunCopySource(JSRunRef ref)
229 {
230     CFStringRef result = 0;
231     JSRun* ptr = (JSRun*)ref;
232     if (ptr)
233     {
234         result = UStringToCFString(ptr->GetSource());
235     }
236     return result;
237 }
238
239
240 /*
241     JSRunCopyGlobalObject
242 */
243 JSObjectRef JSRunCopyGlobalObject(JSRunRef ref)
244 {
245     JSObjectRef result = 0;
246     JSRun* ptr = (JSRun*)ref;
247     if (ptr)
248     {
249         ObjectImp *globalObject = ptr->GlobalObject();
250         result = (JSObjectRef)KJSValueToJSObject(globalObject, ptr->GetInterpreter()->globalExec());
251     }
252     return result;
253 }
254
255 /*
256     JSRunEvaluate
257 */
258 JSObjectRef JSRunEvaluate(JSRunRef ref)
259 {
260     JSObjectRef result = 0;
261     JSRun* ptr = (JSRun*)ref;
262     if (ptr)
263     {
264         Completion completion = ptr->Evaluate();
265         if (completion.isValueCompletion())
266         {
267             result = (JSObjectRef)KJSValueToJSObject(completion.value(), ptr->GetInterpreter()->globalExec());
268         }
269
270         if (completion.complType() == Throw)
271         {
272             JSFlags flags = ptr->Flags();
273             if (flags & kJSFlagDebug)
274             {
275                 CFTypeRef error = JSObjectCopyCFValue(result);
276                 if (error)
277                 {
278                     CFShow(error);
279                     CFRelease(error);
280                 }
281             }
282         }
283     }
284     return result;
285 }
286
287 /*
288     JSRunCheckSyntax
289     Return true if no syntax error
290 */
291 bool JSRunCheckSyntax(JSRunRef ref)
292 {
293     bool result = false;
294     JSRun* ptr = (JSRun*)ref;
295     if (ptr)
296     {
297             JSLockInterpreter();
298             result = ptr->CheckSyntax();
299             JSUnlockInterpreter();
300     }
301     return result;
302 }
303
304 /*
305     JSCollect - trigger garbage collection
306 */
307 void JSCollect(void)
308 {
309     InterpreterLock lock;
310     Collector::collect();
311 }
312
313 /*
314     JSTypeGetCFArrayCallBacks
315 */
316 void JSTypeGetCFArrayCallBacks(CFArrayCallBacks* outCallBacks)
317 {
318     if (outCallBacks)
319     {
320         outCallBacks->version = 1;
321         outCallBacks->retain = (CFArrayRetainCallBack)JSCFRetain;
322         outCallBacks->release = (CFArrayReleaseCallBack)JSCFRelease;
323         outCallBacks->copyDescription = (CFArrayCopyDescriptionCallBack)JSCopyDescription;
324         outCallBacks->equal = (CFArrayEqualCallBack)JSEqual;
325     }
326 }
327
328
329 /*
330     JSCFRetain
331 */
332 void *JSCFRetain(CFAllocatorRef allocator, const void *value)
333 {
334     JSRetain((JSTypeRef)value);
335     return (void*)value;
336 }
337
338 /*
339     JSCFRelease
340 */
341 void JSCFRelease(CFAllocatorRef allocator, const void *value)
342 {
343     JSRelease((JSTypeRef)value);
344 }
345
346
347 /*
348     JSObjectCreateWithCFType
349 */
350 JSObjectRef JSObjectCreateWithCFType(CFTypeRef inRef)
351 {
352     JSObjectCallBacks callBacks;
353     JSObjectRef cfJSObject = nil;
354     if (inRef)
355     {
356         callBacks.dispose = CFJSObjectDispose;
357         callBacks.equal = CFJSObjectEqual;
358         callBacks.copyCFValue = CFJSObjectCopyCFValue;
359         callBacks.copyProperty = CFJSObjectCopyProperty;
360         callBacks.setProperty = CFJSObjectSetProperty;
361         callBacks.callFunction = 0;
362         callBacks.copyPropertyNames = CFJSObjectCopyPropertyNames;
363         cfJSObject = JSObjectCreateInternal((void*)CFRetain(inRef), &callBacks, 0, kJSUserObjectDataTypeCFType );
364     }
365     return cfJSObject;
366 }
367
368 /*
369     CFJSObjectDispose
370 */
371 void CFJSObjectDispose(void *data)
372 {
373     if (data)
374     {
375         CFRelease((JSTypeRef)data);
376     }
377 }
378
379 CFArrayRef JSObjectCopyPropertyNames(JSObjectRef ref)
380 {
381     CFArrayRef result = 0;
382     JSUserObject* ptr = (JSUserObject*)ref;
383     if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
384     {
385         result = ptr->CopyPropertyNames();
386     }
387     return result;
388 }
389 /*
390     CFJSObjectCopyProperty
391 */
392 JSObjectRef CFJSObjectCopyProperty(void *data, CFStringRef propertyName)
393 {
394     JSObjectRef result = 0;
395     if (data && propertyName)
396     {
397         CFTypeRef cfResult = 0;
398         if (CFGetTypeID(data) == CFDictionaryGetTypeID())
399         {
400             if (CFStringCompare(propertyName, CFSTR("length"), 0) == kCFCompareEqualTo)
401             {
402                 int len = CFDictionaryGetCount((CFDictionaryRef)data);
403                 cfResult = CFNumberCreate(0, kCFNumberIntType, &len);
404             }
405             else
406             {
407                 cfResult = RetainCFType(CFDictionaryGetValue((CFDictionaryRef)data, propertyName));
408             }
409         }
410         else if (CFGetTypeID(data) == CFArrayGetTypeID())
411         {
412             if (CFStringCompare(propertyName, CFSTR("length"), 0) == kCFCompareEqualTo)
413             {
414                 int len = CFArrayGetCount((CFArrayRef)data);
415                 cfResult = CFNumberCreate(0, kCFNumberIntType, &len);
416             }
417             else
418             {
419                 SInt32 index = CFStringGetIntValue(propertyName);
420                 CFIndex arrayCount = CFArrayGetCount((CFArrayRef)data);
421                 if (index >= 0 && index < arrayCount)
422                 {
423                     cfResult = RetainCFType(CFArrayGetValueAtIndex((CFArrayRef)data, index));
424                 }
425             }
426         }
427         else if (CFGetTypeID(data) == CFStringGetTypeID())
428         {
429             if (CFStringCompare(propertyName, CFSTR("length"), 0) == kCFCompareEqualTo)
430             {
431                 int len = CFStringGetLength((CFStringRef)data);
432                 cfResult = CFNumberCreate(0, kCFNumberIntType, &len);
433             }
434         }
435         if (cfResult)
436         {
437             result = JSObjectCreateWithCFType(cfResult);
438             CFRelease(cfResult);
439         }
440     }
441     return result;
442 }
443
444
445 /*
446     CFJSObjectSetProperty
447 */
448 void CFJSObjectSetProperty(void *data, CFStringRef propertyName, JSObjectRef jsValue)
449 {
450     if (data && propertyName)
451     {
452         CFTypeRef cfValue = JSObjectCopyCFValue(jsValue);
453
454         if (cfValue)
455         {
456             if (CFGetTypeID(data) == CFDictionaryGetTypeID())
457             {
458                 CFDictionarySetValue((CFMutableDictionaryRef)data, propertyName, cfValue);
459             }
460             else if (CFGetTypeID(data) == CFArrayGetTypeID())
461             {
462                 SInt32 index = CFStringGetIntValue(propertyName);
463                 CFIndex arrayCount = CFArrayGetCount((CFArrayRef)data);
464                 if (index >= 0)
465                 {
466                     for (; arrayCount < index; arrayCount++)
467                     {
468                         CFArrayAppendValue((CFMutableArrayRef)data, GetCFNull());
469                     }
470                     CFArraySetValueAtIndex((CFMutableArrayRef)data, index, cfValue);
471                 }
472             }
473             CFRelease(cfValue);
474         }
475         else
476         {
477             if (CFGetTypeID(data) == CFDictionaryGetTypeID())
478             {
479                 CFDictionaryRemoveValue((CFMutableDictionaryRef)data, propertyName);
480             }
481             else if (CFGetTypeID(data) == CFArrayGetTypeID())
482             {
483                 SInt32 index = CFStringGetIntValue(propertyName);
484                 CFIndex arrayCount = CFArrayGetCount((CFArrayRef)data);
485                 if (index >= 0)
486                 {
487                     for (; arrayCount < index; arrayCount++)
488                     {
489                         CFArrayAppendValue((CFMutableArrayRef)data, GetCFNull());
490                     }
491                     CFArraySetValueAtIndex((CFMutableArrayRef)data, index, GetCFNull());
492                 }
493             }
494         }
495     }
496 }
497
498
499 /*
500     CFJSObjectCopyCFValue
501 */
502 CFTypeRef CFJSObjectCopyCFValue(void *data)
503 {
504     CFTypeRef result = 0;
505     if (data)
506     {
507         result = (CFTypeRef)CFRetain(data);
508     }
509     return result;
510 }
511
512 /*
513     CFJSObjectCopyCFValue
514 */
515 UInt8 CFJSObjectEqual(void *data1, void *data2)
516 {
517     UInt8 result = false;
518     if (data1 && data2)
519     {
520         CFEqual((CFTypeRef)data1, (CFTypeRef)data2);
521     }
522     return result;
523 }
524
525
526 /*
527     CFJSObjectCopyPropertyNames
528 */
529 CFArrayRef CFJSObjectCopyPropertyNames(void *data)
530 {
531     CFMutableArrayRef result = 0;
532     if (data)
533     {
534         CFTypeID cfType = CFGetTypeID(data);
535         if (cfType == CFDictionaryGetTypeID())
536         {
537             CFIndex count = CFDictionaryGetCount((CFDictionaryRef)data);
538             if (count)
539             {
540                 CFTypeRef* keys = (CFTypeRef*)malloc(sizeof(CFTypeRef)*count);
541                 if (keys)
542                 {
543                     int i;
544                     CFDictionaryGetKeysAndValues((CFDictionaryRef)data, (const void **)keys, 0);
545                     for (i = 0; i < count; i++)
546                     {
547                         CFStringRef key = (CFStringRef)keys[i];
548                         if (CFGetTypeID(key) != CFStringGetTypeID()) continue;
549
550                         if (!result) result = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
551                         if (!result) continue;
552
553                         CFArrayAppendValue(result, key);
554                     }
555                     free(keys);
556                 }
557             }
558         }
559     }
560     return result;
561 }
562
563
564
565
566 CFMutableArrayRef JSCreateCFArrayFromJSArray(CFArrayRef array)
567 {
568     CFIndex count = array ? CFArrayGetCount(array) : 0;
569     CFMutableArrayRef cfArray = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
570     CFIndex i;
571
572     for (i = 0; cfArray && i <  count; i++)
573     {
574         JSObjectRef jsValue = (JSObjectRef)CFArrayGetValueAtIndex(array, i);
575         CFTypeRef cfvalue = JSObjectCopyCFValue(jsValue);
576         if (cfvalue)
577         {
578             CFArrayAppendValue(cfArray, cfvalue);
579             CFRelease(cfvalue);
580         }
581         else
582         {
583             CFArrayAppendValue(cfArray, GetCFNull());
584         }
585     }
586     return cfArray;
587 }
588
589 CFMutableArrayRef JSCreateJSArrayFromCFArray(CFArrayRef array)
590 {
591     CFIndex count = array ? CFArrayGetCount(array) : 0;
592     CFArrayCallBacks arrayCallbacks;
593     CFMutableArrayRef jsArray;
594     CFIndex i;
595
596     JSTypeGetCFArrayCallBacks(&arrayCallbacks);
597     jsArray = CFArrayCreateMutable(0, 0, &arrayCallbacks);
598
599     for (i = 0; array && i <  count; i++)
600     {
601         CFTypeRef cfValue = (CFTypeRef)CFArrayGetValueAtIndex(array, i);
602         JSObjectRef jsValue = JSObjectCreateWithCFType(cfValue);
603
604         if (!jsValue) jsValue = JSObjectCreateWithCFType(GetCFNull());
605         if (jsValue)
606         {
607             CFArrayAppendValue(jsArray, jsValue);
608             JSRelease(jsValue);
609         }
610     }
611     return jsArray;
612 }
613
614
615 void JSLockInterpreter()
616 {
617     Interpreter::lock();
618 }
619
620
621 void JSUnlockInterpreter()
622 {
623     Interpreter::unlock();
624 }