Rubber stamped by hyatt.
[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 = NULL;
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 = NULL;
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, NULL, 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 = NULL;
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 = NULL;
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 = NULL;
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 = NULL;
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 = NULL;
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 = NULL;
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 = NULL;
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 = NULL;
246         JSRun* ptr = (JSRun*)ref;
247         if (ptr)
248         {
249                 Object 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 = NULL;
261         JSRun* ptr = (JSRun*)ref;
262         if (ptr)
263         {
264                 Completion completion = ptr->Evaluate();
265 #if JAG_PINK_OR_LATER
266
267                 if (completion.isValueCompletion())
268                 {
269                         result = (JSObjectRef)KJSValueToJSObject(completion.value(), ptr->GetInterpreter()->globalExec());
270                 }
271
272                 if (completion.complType() == Throw)    
273                 {
274                         JSFlags flags = ptr->Flags();
275                         if (flags & kJSFlagDebug)
276                         {
277                                 CFTypeRef error = JSObjectCopyCFValue(result);
278                                 if (error)
279                                 {
280                                         CFShow(error);
281                                         CFRelease(error);
282                                 }
283                         }
284                 }
285
286 #else
287                 result = (JSObjectRef)KJSValueToJSObject(completion, ptr->GetInterpreter()->globalExec());              
288 #endif
289         }
290         return result;
291 }
292
293 /*
294         JSRunCheckSyntax
295         Return true if no syntax error
296 */
297 bool JSRunCheckSyntax(JSRunRef ref)
298 {
299 #if JAG_PINK_OR_LATER
300         bool result = false;
301         JSRun* ptr = (JSRun*)ref;
302         if (ptr)
303         {
304             JSLockInterpreter();
305             result = ptr->CheckSyntax();
306             JSUnlockInterpreter();
307         }
308         return result;
309 #else
310         return true;
311 #endif
312 }
313
314 /*
315         JSCollect - trigger garbage collection
316 */
317 void JSCollect(void)
318 {
319 #if JAG_PINK_OR_LATER
320         Interpreter::lock();
321         Collector::collect();
322         Interpreter::unlock(); 
323 #endif
324 }
325
326 /*
327         JSTypeGetCFArrayCallBacks
328 */
329 void JSTypeGetCFArrayCallBacks(CFArrayCallBacks* outCallBacks)
330 {
331         if (outCallBacks)
332         {
333                 outCallBacks->version = 1;
334                 outCallBacks->retain = (CFArrayRetainCallBack)JSCFRetain;
335                 outCallBacks->release = (CFArrayReleaseCallBack)JSCFRelease;
336                 outCallBacks->copyDescription = (CFArrayCopyDescriptionCallBack)JSCopyDescription;
337                 outCallBacks->equal = (CFArrayEqualCallBack)JSEqual;
338         }
339 }
340
341
342 /*
343         JSCFRetain
344 */
345 void* JSCFRetain(CFAllocatorRef allocator, const void *value)
346 {
347         JSRetain((JSTypeRef)value);
348         return (void*)value;
349 }
350
351 /*
352         JSCFRelease
353 */
354 void JSCFRelease(CFAllocatorRef allocator, const void *value)
355 {
356         JSRelease((JSTypeRef)value);
357 }
358
359
360 /*
361         JSObjectCreateWithCFType
362 */
363 JSObjectRef JSObjectCreateWithCFType(CFTypeRef inRef)
364 {
365         JSObjectCallBacks callBacks;
366         JSObjectRef cfJSObject = nil;
367         if (inRef)
368         {
369                 callBacks.dispose = CFJSObjectDispose;
370                 callBacks.equal = CFJSObjectEqual;
371                 callBacks.copyCFValue = CFJSObjectCopyCFValue;
372                 callBacks.copyProperty = CFJSObjectCopyProperty;
373                 callBacks.setProperty = CFJSObjectSetProperty;
374                 callBacks.callFunction = NULL;
375                 callBacks.copyPropertyNames = CFJSObjectCopyPropertyNames;
376                 cfJSObject = JSObjectCreateInternal((void*)CFRetain(inRef), &callBacks, NULL, kJSUserObjectDataTypeCFType );
377         }
378         return cfJSObject;
379 }
380
381 /*
382         CFJSObjectDispose
383 */
384 void CFJSObjectDispose(void* data)
385 {
386         if (data)
387         {
388                 CFRelease((JSTypeRef)data);
389         }
390 }
391
392 CFArrayRef JSObjectCopyPropertyNames(JSObjectRef ref)
393 {
394         CFArrayRef result = NULL;
395         JSUserObject* ptr = (JSUserObject*)ref;
396         if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
397         {
398                 result = ptr->CopyPropertyNames();
399         }
400         return result;
401 }
402 /*
403         CFJSObjectCopyProperty
404 */
405 JSObjectRef CFJSObjectCopyProperty(void* data, CFStringRef propertyName)
406 {
407         JSObjectRef result = NULL;
408         if (data && propertyName)
409         {
410                 CFTypeRef cfResult = NULL;
411                 if (CFGetTypeID(data) == CFDictionaryGetTypeID())
412                 {
413                         if (CFStringCompare(propertyName, CFSTR("length"), 0) == kCFCompareEqualTo)
414                         {
415                                 int len = CFDictionaryGetCount((CFDictionaryRef)data);
416                                 cfResult = CFNumberCreate(NULL, kCFNumberIntType, &len);
417                         }
418                         else
419                         {
420                                 cfResult = RetainCFType(CFDictionaryGetValue((CFDictionaryRef)data, propertyName));
421                         }
422                 }
423                 else if (CFGetTypeID(data) == CFArrayGetTypeID())
424                 {
425                         if (CFStringCompare(propertyName, CFSTR("length"), 0) == kCFCompareEqualTo)
426                         {
427                                 int len = CFArrayGetCount((CFArrayRef)data);
428                                 cfResult = CFNumberCreate(NULL, kCFNumberIntType, &len);
429                         }
430                         else
431                         {
432                                 SInt32 index = CFStringGetIntValue(propertyName);       
433                                 CFIndex arrayCount = CFArrayGetCount((CFArrayRef)data);
434                                 if (index >= 0 && index < arrayCount)
435                                 {
436                                         cfResult = RetainCFType(CFArrayGetValueAtIndex((CFArrayRef)data, index));
437                                 }
438                         }
439                 }
440                 else if (CFGetTypeID(data) == CFStringGetTypeID())
441                 {
442                         if (CFStringCompare(propertyName, CFSTR("length"), 0) == kCFCompareEqualTo)
443                         {
444                                 int len = CFStringGetLength((CFStringRef)data);
445                                 cfResult = CFNumberCreate(NULL, kCFNumberIntType, &len);
446                         }
447                 }
448                 if (cfResult)
449                 {
450                         result = JSObjectCreateWithCFType(cfResult);
451                         CFRelease(cfResult);
452                 }
453         }
454         return result;
455 }
456
457
458 /*
459         CFJSObjectSetProperty
460 */
461 void CFJSObjectSetProperty(void* data, CFStringRef propertyName, JSObjectRef jsValue)
462 {
463         if (data && propertyName)
464         {
465                 CFTypeRef cfValue = JSObjectCopyCFValue(jsValue);
466
467                 if (cfValue)
468                 {
469                         if (CFGetTypeID(data) == CFDictionaryGetTypeID())
470                         {
471                                 CFDictionarySetValue((CFMutableDictionaryRef)data, propertyName, cfValue);
472                         }
473                         else if (CFGetTypeID(data) == CFArrayGetTypeID())
474                         {
475                                 SInt32 index = CFStringGetIntValue(propertyName);       
476                                 CFIndex arrayCount = CFArrayGetCount((CFArrayRef)data);
477                                 if (index >= 0)
478                                 {
479                                         for (; arrayCount < index; arrayCount++)
480                                         {
481                                                 CFArrayAppendValue((CFMutableArrayRef)data, GetCFNull());
482                                         }
483                                         CFArraySetValueAtIndex((CFMutableArrayRef)data, index, cfValue);                                        
484                                 }
485                         }               
486                         CFRelease(cfValue);
487                 }
488                 else
489                 {
490                         if (CFGetTypeID(data) == CFDictionaryGetTypeID())
491                         {
492                                 CFDictionaryRemoveValue((CFMutableDictionaryRef)data, propertyName);
493                         }
494                         else if (CFGetTypeID(data) == CFArrayGetTypeID())
495                         {
496                                 SInt32 index = CFStringGetIntValue(propertyName);                               
497                                 CFIndex arrayCount = CFArrayGetCount((CFArrayRef)data);
498                                 if (index >= 0)
499                                 {
500                                         for (; arrayCount < index; arrayCount++)
501                                         {
502                                                 CFArrayAppendValue((CFMutableArrayRef)data, GetCFNull());
503                                         }
504                                         CFArraySetValueAtIndex((CFMutableArrayRef)data, index, GetCFNull());                                    
505                                 }                               
506                         }
507                 }
508         }
509 }
510
511
512 /*
513         CFJSObjectCopyCFValue
514 */
515 CFTypeRef CFJSObjectCopyCFValue(void* data)
516 {
517         CFTypeRef result = NULL;
518         if (data)
519         {
520                 result = (CFTypeRef)CFRetain(data);
521         }
522         return result;
523 }
524
525 /*
526         CFJSObjectCopyCFValue
527 */
528 UInt8 CFJSObjectEqual(void* data1, void* data2)
529 {
530         UInt8 result = false;
531         if (data1 && data2)
532         {
533                 CFEqual((CFTypeRef)data1, (CFTypeRef)data2);
534         }
535         return result;
536 }
537
538
539 /*
540         CFJSObjectCopyPropertyNames
541 */
542 CFArrayRef CFJSObjectCopyPropertyNames(void* data)
543 {
544         CFMutableArrayRef result = NULL;
545         if (data)
546         {
547                 CFTypeID cfType = CFGetTypeID(data);
548                 if (cfType == CFDictionaryGetTypeID())
549                 {
550                         CFIndex count = CFDictionaryGetCount((CFDictionaryRef)data);
551                         if (count)
552                         {
553                                 CFTypeRef* keys = (CFTypeRef*)malloc(sizeof(CFTypeRef)*count);
554                                 if (keys)
555                                 {
556                                         int i;
557                                         CFDictionaryGetKeysAndValues((CFDictionaryRef)data, (const void **)keys, NULL);
558                                         for (i = 0; i < count; i++)
559                                         {
560                                                 CFStringRef key = (CFStringRef)keys[i];
561                                                 if (CFGetTypeID(key) != CFStringGetTypeID()) continue;
562
563                                                 if (!result) result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
564                                                 if (!result) continue;
565                                                 
566                                                 CFArrayAppendValue(result, key);
567                                         }
568                                         free(keys);
569                                 }
570                         }
571                 }
572         }
573         return result;
574 }
575
576
577
578
579 CFMutableArrayRef JSCreateCFArrayFromJSArray(CFArrayRef array)
580 {
581         CFIndex count = array ? CFArrayGetCount(array) : 0;
582         CFMutableArrayRef cfArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
583         CFIndex i;
584
585         for (i = 0; cfArray && i <  count; i++)
586         {
587                 JSObjectRef jsValue = (JSObjectRef)CFArrayGetValueAtIndex(array, i);
588                 CFTypeRef cfvalue = JSObjectCopyCFValue(jsValue);
589                 if (cfvalue)
590                 {
591                         CFArrayAppendValue(cfArray, cfvalue);
592                         CFRelease(cfvalue);
593                 }
594                 else
595                 {
596                         CFArrayAppendValue(cfArray, GetCFNull());
597                 }
598         }
599         return cfArray;
600 }
601
602 CFMutableArrayRef JSCreateJSArrayFromCFArray(CFArrayRef array)
603 {
604         CFIndex count = array ? CFArrayGetCount(array) : 0;
605         CFArrayCallBacks arrayCallbacks;
606         CFMutableArrayRef jsArray;
607         CFIndex i;
608
609         JSTypeGetCFArrayCallBacks(&arrayCallbacks);
610         jsArray = CFArrayCreateMutable(NULL, 0, &arrayCallbacks);
611
612         for (i = 0; array && i <  count; i++)
613         {
614                 CFTypeRef cfValue = (CFTypeRef)CFArrayGetValueAtIndex(array, i);
615                 JSObjectRef jsValue = JSObjectCreateWithCFType(cfValue);
616                 
617                 if (!jsValue) jsValue = JSObjectCreateWithCFType(GetCFNull());
618                 if (jsValue)
619                 {
620                         CFArrayAppendValue(jsArray, jsValue);
621                         JSRelease(jsValue);
622                 }
623         }
624         return jsArray;
625 }
626
627
628 void JSLockInterpreter()
629 {
630 #if JAG_PINK_OR_LATER
631         Interpreter::lock();
632 #endif
633 }
634
635
636 void JSUnlockInterpreter()
637 {
638 #if JAG_PINK_OR_LATER
639         Interpreter::unlock();
640 #endif
641 }
642