6c1187429b04536e1bb5d994bb272e30ea49a063
[WebKit-https.git] / Source / WebCore / bridge / qt / qt_runtime_qt4.cpp
1 /*
2  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
3  *
4  *  This library is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU Lesser General Public
6  *  License as published by the Free Software Foundation; either
7  *  version 2 of the License, or (at your option) any later version.
8  *
9  *  This library is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  Lesser General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Lesser General Public
15  *  License along with this library; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  *
18  */
19
20 #include "config.h"
21 #include "qt_runtime.h"
22
23 #include "APICast.h"
24 #include "BooleanObject.h"
25 #include "DateInstance.h"
26 #include "DatePrototype.h"
27 #include "FunctionPrototype.h"
28 #include "Interpreter.h"
29 #include "JSArray.h"
30 #include "JSDocument.h"
31 #include "JSDOMBinding.h"
32 #include "JSDOMWindow.h"
33 #include <JSFunction.h>
34 #include "JSGlobalObject.h"
35 #include "JSHTMLElement.h"
36 #include "JSLock.h"
37 #include "JSObject.h"
38 #include "JSRetainPtr.h"
39 #include "JSUint8ClampedArray.h"
40 #include "ObjectPrototype.h"
41 #include "PropertyNameArray.h"
42 #include "RegExpConstructor.h"
43 #include "RegExpObject.h"
44 #include "qdatetime.h"
45 #include "qdebug.h"
46 #include "qmetaobject.h"
47 #include "qmetatype.h"
48 #include "qobject.h"
49 #include "qstringlist.h"
50 #include "qt_instance.h"
51 #include "qt_pixmapruntime.h"
52 #include "qvarlengtharray.h"
53
54 #include <wtf/DateMath.h>
55
56 #include <limits.h>
57 #include <runtime/Error.h>
58 #include <runtime_array.h>
59 #include <runtime_object.h>
60
61 // QtScript has these
62 Q_DECLARE_METATYPE(QObjectList);
63 Q_DECLARE_METATYPE(QList<int>);
64 Q_DECLARE_METATYPE(QVariant);
65
66 using namespace WebCore;
67
68 namespace JSC {
69 namespace Bindings {
70
71 // Debugging
72 //#define QTWK_RUNTIME_CONVERSION_DEBUG
73 //#define QTWK_RUNTIME_MATCH_DEBUG
74
75 class QWKNoDebug
76 {
77 public:
78     inline QWKNoDebug(){}
79     inline ~QWKNoDebug(){}
80
81     template<typename T>
82     inline QWKNoDebug &operator<<(const T &) { return *this; }
83 };
84
85 #ifdef QTWK_RUNTIME_CONVERSION_DEBUG
86 #define qConvDebug() qDebug()
87 #else
88 #define qConvDebug() QWKNoDebug()
89 #endif
90
91 #ifdef QTWK_RUNTIME_MATCH_DEBUG
92 #define qMatchDebug() qDebug()
93 #else
94 #define qMatchDebug() QWKNoDebug()
95 #endif
96
97 typedef enum {
98     Variant = 0,
99     Number,
100     Boolean,
101     String,
102     Date,
103     RegExp,
104     Array,
105     QObj,
106     Object,
107     Null,
108     RTArray,
109     JSUint8ClampedArrayType
110 } JSRealType;
111
112 #if defined(QTWK_RUNTIME_CONVERSION_DEBUG) || defined(QTWK_RUNTIME_MATCH_DEBUG)
113 QDebug operator<<(QDebug dbg, const JSRealType &c)
114 {
115      const char *map[] = { "Variant", "Number", "Boolean", "String", "Date",
116          "RegExp", "Array", "RTObject", "Object", "Null", "RTArray"};
117
118      dbg.nospace() << "JSType(" << ((int)c) << ", " <<  map[c] << ")";
119
120      return dbg.space();
121 }
122 #endif
123
124 struct RuntimeConversion {
125     ConvertToJSValueFunction toJSValueFunc;
126     ConvertToVariantFunction toVariantFunc;
127 };
128
129 typedef QHash<int, RuntimeConversion> RuntimeConversionTable;
130 Q_GLOBAL_STATIC(RuntimeConversionTable, customRuntimeConversions)
131
132 void registerCustomType(int qtMetaTypeId, ConvertToVariantFunction toVariantFunc, ConvertToJSValueFunction toJSValueFunc)
133 {
134     RuntimeConversion conversion;
135     conversion.toJSValueFunc = toJSValueFunc;
136     conversion.toVariantFunc = toVariantFunc;
137     customRuntimeConversions()->insert(qtMetaTypeId, conversion);
138 }
139
140 static bool isJSUint8ClampedArray(JSValue val)
141 {
142     return val.isCell() && val.inherits(&JSUint8ClampedArray::s_info);
143 }
144
145 static JSRealType valueRealType(ExecState* exec, JSValue val)
146 {
147     if (val.isNumber())
148         return Number;
149     else if (val.isString())
150         return String;
151     else if (val.isBoolean())
152         return Boolean;
153     else if (val.isNull())
154         return Null;
155     else if (isJSUint8ClampedArray(val))
156         return JSUint8ClampedArrayType;
157     else if (val.isObject()) {
158         JSObject *object = val.toObject(exec);
159         if (object->inherits(&RuntimeArray::s_info))  // RuntimeArray 'inherits' from Array, but not in C++
160             return RTArray;
161         else if (object->inherits(&JSArray::s_info))
162             return Array;
163         else if (object->inherits(&DateInstance::s_info))
164             return Date;
165         else if (object->inherits(&RegExpObject::s_info))
166             return RegExp;
167         else if (object->inherits(&RuntimeObject::s_info))
168             return QObj;
169         return Object;
170     }
171
172     return String; // I don't know.
173 }
174
175 QVariant convertValueToQVariant(ExecState*, JSValue, QMetaType::Type, int*, HashSet<JSObject*>*, int);
176
177 static QVariantMap convertValueToQVariantMap(ExecState* exec, JSObject* object, HashSet<JSObject*>* visitedObjects, int recursionLimit)
178 {
179     Q_ASSERT(!exec->hadException());
180
181     PropertyNameArray properties(exec);
182     object->methodTable()->getPropertyNames(object, exec, properties, ExcludeDontEnumProperties);
183     PropertyNameArray::const_iterator it = properties.begin();
184     QVariantMap result;
185     int objdist = 0;
186
187     while (it != properties.end()) {
188         if (object->propertyIsEnumerable(exec, *it)) {
189             JSValue val = object->get(exec, *it);
190             if (exec->hadException())
191                 exec->clearException();
192             else {
193                 QVariant v = convertValueToQVariant(exec, val, QMetaType::Void, &objdist, visitedObjects, recursionLimit);
194                 if (objdist >= 0) {
195                     UString ustring = (*it).ustring();
196                     QString id = QString((const QChar*)ustring.impl()->characters(), ustring.length());
197                     result.insert(id, v);
198                 }
199             }
200         }
201         ++it;
202     }
203     return result;
204 }
205
206 QVariant convertValueToQVariant(ExecState* exec, JSValue value, QMetaType::Type hint, int *distance, HashSet<JSObject*>* visitedObjects, int recursionLimit)
207 {
208     --recursionLimit;
209
210     if (!value || !recursionLimit)
211         return QVariant();
212
213     JSObject* object = 0;
214     if (value.isObject()) {
215         object = value.toObject(exec);
216         if (visitedObjects->contains(object))
217             return QVariant();
218
219         visitedObjects->add(object);
220     }
221
222     // check magic pointer values before dereferencing value
223     if (value == jsNaN()
224         || (value == jsUndefined()
225             && hint != QMetaType::QString
226             && hint != (QMetaType::Type) qMetaTypeId<QVariant>())) {
227         if (distance)
228             *distance = -1;
229         return QVariant();
230     }
231
232     JSLock lock(SilenceAssertionsOnly);
233     JSRealType type = valueRealType(exec, value);
234     if (hint == QMetaType::Void) {
235         switch(type) {
236             case Number:
237                 hint = QMetaType::Double;
238                 break;
239             case Boolean:
240                 hint = QMetaType::Bool;
241                 break;
242             case String:
243             default:
244                 hint = QMetaType::QString;
245                 break;
246             case Date:
247                 hint = QMetaType::QDateTime;
248                 break;
249             case RegExp:
250                 hint = QMetaType::QRegExp;
251                 break;
252             case Object:
253                 if (object->inherits(&NumberObject::s_info))
254                     hint = QMetaType::Double;
255                 else if (object->inherits(&BooleanObject::s_info))
256                     hint = QMetaType::Bool;
257                 else
258                     hint = QMetaType::QVariantMap;
259                 break;
260             case QObj:
261                 hint = QMetaType::QObjectStar;
262                 break;
263             case JSUint8ClampedArrayType:
264                 hint = QMetaType::QByteArray;
265                 break;
266             case Array:
267             case RTArray:
268                 hint = QMetaType::QVariantList;
269                 break;
270         }
271     }
272
273     qConvDebug() << "convertValueToQVariant: jstype is " << type << ", hint is" << hint;
274
275     if (value == jsNull()
276         && hint != QMetaType::QObjectStar
277         && hint != QMetaType::VoidStar
278         && hint != QMetaType::QString
279         && hint != (QMetaType::Type) qMetaTypeId<QVariant>()) {
280         if (distance)
281             *distance = -1;
282         return QVariant();
283     }
284
285     QVariant ret;
286     int dist = -1;
287     switch (hint) {
288         case QMetaType::Bool:
289             if (type == Object && object->inherits(&BooleanObject::s_info))
290                 ret = QVariant(asBooleanObject(value)->internalValue().toBoolean());
291             else
292                 ret = QVariant(value.toBoolean());
293             if (type == Boolean)
294                 dist = 0;
295             else
296                 dist = 10;
297             break;
298
299         case QMetaType::Int:
300         case QMetaType::UInt:
301         case QMetaType::Long:
302         case QMetaType::ULong:
303         case QMetaType::LongLong:
304         case QMetaType::ULongLong:
305         case QMetaType::Short:
306         case QMetaType::UShort:
307         case QMetaType::Float:
308         case QMetaType::Double:
309             ret = QVariant(value.toNumber(exec));
310             ret.convert((QVariant::Type)hint);
311             if (type == Number) {
312                 switch (hint) {
313                 case QMetaType::Double:
314                     dist = 0;
315                     break;
316                 case QMetaType::Float:
317                     dist = 1;
318                     break;
319                 case QMetaType::LongLong:
320                 case QMetaType::ULongLong:
321                     dist = 2;
322                     break;
323                 case QMetaType::Long:
324                 case QMetaType::ULong:
325                     dist = 3;
326                     break;
327                 case QMetaType::Int:
328                 case QMetaType::UInt:
329                     dist = 4;
330                     break;
331                 case QMetaType::Short:
332                 case QMetaType::UShort:
333                     dist = 5;
334                     break;
335                     break;
336                 default:
337                     dist = 10;
338                     break;
339                 }
340             } else {
341                 dist = 10;
342             }
343             break;
344
345         case QMetaType::QChar:
346             if (type == Number || type == Boolean) {
347                 ret = QVariant(QChar((ushort)value.toNumber(exec)));
348                 if (type == Boolean)
349                     dist = 3;
350                 else
351                     dist = 6;
352             } else {
353                 UString str = value.toString(exec)->value(exec);
354                 ret = QVariant(QChar(str.length() ? *(const ushort*)str.impl()->characters() : 0));
355                 if (type == String)
356                     dist = 3;
357                 else
358                     dist = 10;
359             }
360             break;
361
362         case QMetaType::QString: {
363             if (value.isUndefinedOrNull()) {
364                 if (distance)
365                     *distance = 1;
366                 return QString();
367             } else {
368                 UString ustring = value.toString(exec)->value(exec);
369                 ret = QVariant(QString((const QChar*)ustring.impl()->characters(), ustring.length()));
370                 if (type == String)
371                     dist = 0;
372                 else
373                     dist = 10;
374             }
375             break;
376         }
377
378         case QMetaType::QVariantMap:
379             if (type == Object || type == Array || type == RTArray) {
380                 ret = QVariant(convertValueToQVariantMap(exec, object, visitedObjects, recursionLimit));
381                 // Those types can still have perfect matches, e.g. 'bool' if value is a Boolean Object.
382                 dist = 1;
383             }
384             break;
385
386         case QMetaType::QVariantList:
387             if (type == RTArray) {
388                 RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
389
390                 QVariantList result;
391                 int len = rtarray->getLength();
392                 int objdist = 0;
393                 qConvDebug() << "converting a " << len << " length Array";
394                 for (int i = 0; i < len; ++i) {
395                     JSValue val = rtarray->getConcreteArray()->valueAt(exec, i);
396                     result.append(convertValueToQVariant(exec, val, QMetaType::Void, &objdist, visitedObjects, recursionLimit));
397                     if (objdist == -1) {
398                         qConvDebug() << "Failed converting element at index " << i;
399                         break; // Failed converting a list entry, so fail the array
400                     }
401                 }
402                 if (objdist != -1) {
403                     dist = 5;
404                     ret = QVariant(result);
405                 }
406             } else if (type == Array) {
407                 JSArray* array = static_cast<JSArray*>(object);
408
409                 QVariantList result;
410                 int len = array->length();
411                 int objdist = 0;
412                 qConvDebug() << "converting a " << len << " length Array";
413                 for (int i = 0; i < len; ++i) {
414                     JSValue val = array->get(exec, i);
415                     result.append(convertValueToQVariant(exec, val, QMetaType::Void, &objdist, visitedObjects, recursionLimit));
416                     if (objdist == -1) {
417                         qConvDebug() << "Failed converting element at index " << i;
418                         break; // Failed converting a list entry, so fail the array
419                     }
420                 }
421                 if (objdist != -1) {
422                     dist = 5;
423                     ret = QVariant(result);
424                 }
425             } else {
426                 // Make a single length array
427                 int objdist;
428                 qConvDebug() << "making a single length variantlist";
429                 QVariant var = convertValueToQVariant(exec, value, QMetaType::Void, &objdist, visitedObjects, recursionLimit);
430                 if (objdist != -1) {
431                     QVariantList result;
432                     result << var;
433                     ret = QVariant(result);
434                     dist = 10;
435                 } else {
436                     qConvDebug() << "failed making single length varlist";
437                 }
438             }
439             break;
440
441         case QMetaType::QStringList: {
442             if (type == RTArray) {
443                 RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
444
445                 QStringList result;
446                 int len = rtarray->getLength();
447                 for (int i = 0; i < len; ++i) {
448                     JSValue val = rtarray->getConcreteArray()->valueAt(exec, i);
449                     UString ustring = val.toString(exec)->value(exec);
450                     QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
451
452                     result.append(qstring);
453                 }
454                 dist = 5;
455                 ret = QVariant(result);
456             } else if (type == Array) {
457                 JSArray* array = static_cast<JSArray*>(object);
458
459                 QStringList result;
460                 int len = array->length();
461                 for (int i = 0; i < len; ++i) {
462                     JSValue val = array->get(exec, i);
463                     UString ustring = val.toString(exec)->value(exec);
464                     QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
465
466                     result.append(qstring);
467                 }
468                 dist = 5;
469                 ret = QVariant(result);
470             } else {
471                 // Make a single length array
472                 UString ustring = value.toString(exec)->value(exec);
473                 QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
474                 QStringList result;
475                 result.append(qstring);
476                 ret = QVariant(result);
477                 dist = 10;
478             }
479             break;
480         }
481
482         case QMetaType::QByteArray: {
483             if (type == JSUint8ClampedArrayType) {
484                 WTF::Uint8ClampedArray* arr = toUint8ClampedArray(value);
485                 ret = QVariant(QByteArray(reinterpret_cast<const char*>(arr->data()), arr->length()));
486                 dist = 0;
487             } else {
488                 UString ustring = value.toString(exec)->value(exec);
489                 ret = QVariant(QString((const QChar*)ustring.impl()->characters(), ustring.length()).toLatin1());
490                 if (type == String)
491                     dist = 5;
492                 else
493                     dist = 10;
494             }
495             break;
496         }
497
498         case QMetaType::QDateTime:
499         case QMetaType::QDate:
500         case QMetaType::QTime:
501             if (type == Date) {
502                 DateInstance* date = static_cast<DateInstance*>(object);
503                 GregorianDateTime gdt;
504                 msToGregorianDateTime(exec, date->internalNumber(), true, gdt);
505                 if (hint == QMetaType::QDateTime) {
506                     ret = QDateTime(QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay), QTime(gdt.hour, gdt.minute, gdt.second), Qt::UTC);
507                     dist = 0;
508                 } else if (hint == QMetaType::QDate) {
509                     ret = QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay);
510                     dist = 1;
511                 } else {
512                     ret = QTime(gdt.hour + 1900, gdt.minute, gdt.second);
513                     dist = 2;
514                 }
515             } else if (type == Number) {
516                 double b = value.toNumber(exec);
517                 GregorianDateTime gdt;
518                 msToGregorianDateTime(exec, b, true, gdt);
519                 if (hint == QMetaType::QDateTime) {
520                     ret = QDateTime(QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay), QTime(gdt.hour, gdt.minute, gdt.second), Qt::UTC);
521                     dist = 6;
522                 } else if (hint == QMetaType::QDate) {
523                     ret = QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay);
524                     dist = 8;
525                 } else {
526                     ret = QTime(gdt.hour, gdt.minute, gdt.second);
527                     dist = 10;
528                 }
529 #ifndef QT_NO_DATESTRING
530             } else if (type == String) {
531                 UString ustring = value.toString(exec)->value(exec);
532                 QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
533
534                 if (hint == QMetaType::QDateTime) {
535                     QDateTime dt = QDateTime::fromString(qstring, Qt::ISODate);
536                     if (!dt.isValid())
537                         dt = QDateTime::fromString(qstring, Qt::TextDate);
538                     if (!dt.isValid())
539                         dt = QDateTime::fromString(qstring, Qt::SystemLocaleDate);
540                     if (!dt.isValid())
541                         dt = QDateTime::fromString(qstring, Qt::LocaleDate);
542                     if (dt.isValid()) {
543                         ret = dt;
544                         dist = 2;
545                     }
546                 } else if (hint == QMetaType::QDate) {
547                     QDate dt = QDate::fromString(qstring, Qt::ISODate);
548                     if (!dt.isValid())
549                         dt = QDate::fromString(qstring, Qt::TextDate);
550                     if (!dt.isValid())
551                         dt = QDate::fromString(qstring, Qt::SystemLocaleDate);
552                     if (!dt.isValid())
553                         dt = QDate::fromString(qstring, Qt::LocaleDate);
554                     if (dt.isValid()) {
555                         ret = dt;
556                         dist = 3;
557                     }
558                 } else {
559                     QTime dt = QTime::fromString(qstring, Qt::ISODate);
560                     if (!dt.isValid())
561                         dt = QTime::fromString(qstring, Qt::TextDate);
562                     if (!dt.isValid())
563                         dt = QTime::fromString(qstring, Qt::SystemLocaleDate);
564                     if (!dt.isValid())
565                         dt = QTime::fromString(qstring, Qt::LocaleDate);
566                     if (dt.isValid()) {
567                         ret = dt;
568                         dist = 3;
569                     }
570                 }
571 #endif // QT_NO_DATESTRING
572             }
573             break;
574
575         case QMetaType::QRegExp:
576             if (type == RegExp) {
577 /*
578                 RegExpObject *re = static_cast<RegExpObject*>(object);
579 */
580                 // Attempt to convert.. a bit risky
581                 UString ustring = value.toString(exec)->value(exec);
582                 QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
583
584                 // this is of the form '/xxxxxx/i'
585                 int firstSlash = qstring.indexOf(QLatin1Char('/'));
586                 int lastSlash = qstring.lastIndexOf(QLatin1Char('/'));
587                 if (firstSlash >=0 && lastSlash > firstSlash) {
588                     QRegExp realRe;
589
590                     realRe.setPattern(qstring.mid(firstSlash + 1, lastSlash - firstSlash - 1));
591
592                     if (qstring.mid(lastSlash + 1).contains(QLatin1Char('i')))
593                         realRe.setCaseSensitivity(Qt::CaseInsensitive);
594
595                     ret = QVariant::fromValue(realRe);
596                     dist = 0;
597                 } else {
598                     qConvDebug() << "couldn't parse a JS regexp";
599                 }
600             } else if (type == String) {
601                 UString ustring = value.toString(exec)->value(exec);
602                 QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
603
604                 QRegExp re(qstring);
605                 if (re.isValid()) {
606                     ret = QVariant::fromValue(re);
607                     dist = 10;
608                 }
609             }
610             break;
611
612         case QMetaType::QObjectStar:
613             if (type == QObj) {
614                 QtInstance* qtinst = QtInstance::getInstance(object);
615                 if (qtinst) {
616                     if (qtinst->getObject()) {
617                         qConvDebug() << "found instance, with object:" << (void*) qtinst->getObject();
618                         ret = QVariant::fromValue(qtinst->getObject());
619                         qConvDebug() << ret;
620                         dist = 0;
621                     } else {
622                         qConvDebug() << "can't convert deleted qobject";
623                     }
624                 } else {
625                     qConvDebug() << "wasn't a qtinstance";
626                 }
627             } else if (type == Null) {
628                 QObject* nullobj = 0;
629                 ret = QVariant::fromValue(nullobj);
630                 dist = 0;
631             } else {
632                 qConvDebug() << "previous type was not an object:" << type;
633             }
634             break;
635
636         case QMetaType::VoidStar:
637             if (type == QObj) {
638                 QtInstance* qtinst = QtInstance::getInstance(object);
639                 if (qtinst) {
640                     if (qtinst->getObject()) {
641                         qConvDebug() << "found instance, with object:" << (void*) qtinst->getObject();
642                         ret = QVariant::fromValue((void *)qtinst->getObject());
643                         qConvDebug() << ret;
644                         dist = 0;
645                     } else {
646                         qConvDebug() << "can't convert deleted qobject";
647                     }
648                 } else {
649                     qConvDebug() << "wasn't a qtinstance";
650                 }
651             } else if (type == Null) {
652                 ret = QVariant::fromValue((void*)0);
653                 dist = 0;
654             } else if (type == Number) {
655                 // I don't think that converting a double to a pointer is a wise
656                 // move.  Except maybe 0.
657                 qConvDebug() << "got number for void * - not converting, seems unsafe:" << value.toNumber(exec);
658             } else {
659                 qConvDebug() << "void* - unhandled type" << type;
660             }
661             break;
662
663         default:
664             // Non const type ids
665             if (hint == (QMetaType::Type) qMetaTypeId<QObjectList>())
666             {
667                 if (type == RTArray) {
668                     RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
669
670                     QObjectList result;
671                     int len = rtarray->getLength();
672                     for (int i = 0; i < len; ++i) {
673                         JSValue val = rtarray->getConcreteArray()->valueAt(exec, i);
674                         int itemdist = -1;
675                         QVariant item = convertValueToQVariant(exec, val, QMetaType::QObjectStar, &itemdist, visitedObjects, recursionLimit);
676                         if (itemdist >= 0)
677                             result.append(item.value<QObject*>());
678                         else
679                             break;
680                     }
681                     // If we didn't fail conversion
682                     if (result.count() == len) {
683                         dist = 5;
684                         ret = QVariant::fromValue(result);
685                     }
686                 } else if (type == Array) {
687                     JSObject* object = value.toObject(exec);
688                     JSArray* array = static_cast<JSArray *>(object);
689                     QObjectList result;
690                     int len = array->length();
691                     for (int i = 0; i < len; ++i) {
692                         JSValue val = array->get(exec, i);
693                         int itemdist = -1;
694                         QVariant item = convertValueToQVariant(exec, val, QMetaType::QObjectStar, &itemdist, visitedObjects, recursionLimit);
695                         if (itemdist >= 0)
696                             result.append(item.value<QObject*>());
697                         else
698                             break;
699                     }
700                     // If we didn't fail conversion
701                     if (result.count() == len) {
702                         dist = 5;
703                         ret = QVariant::fromValue(result);
704                     }
705                 } else {
706                     // Make a single length array
707                     QObjectList result;
708                     int itemdist = -1;
709                     QVariant item = convertValueToQVariant(exec, value, QMetaType::QObjectStar, &itemdist, visitedObjects, recursionLimit);
710                     if (itemdist >= 0) {
711                         result.append(item.value<QObject*>());
712                         dist = 10;
713                         ret = QVariant::fromValue(result);
714                     }
715                 }
716                 break;
717             } else if (hint == (QMetaType::Type) qMetaTypeId<QList<int> >()) {
718                 if (type == RTArray) {
719                     RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
720
721                     QList<int> result;
722                     int len = rtarray->getLength();
723                     for (int i = 0; i < len; ++i) {
724                         JSValue val = rtarray->getConcreteArray()->valueAt(exec, i);
725                         int itemdist = -1;
726                         QVariant item = convertValueToQVariant(exec, val, QMetaType::Int, &itemdist, visitedObjects, recursionLimit);
727                         if (itemdist >= 0)
728                             result.append(item.value<int>());
729                         else
730                             break;
731                     }
732                     // If we didn't fail conversion
733                     if (result.count() == len) {
734                         dist = 5;
735                         ret = QVariant::fromValue(result);
736                     }
737                 } else if (type == Array) {
738                     JSArray* array = static_cast<JSArray *>(object);
739
740                     QList<int> result;
741                     int len = array->length();
742                     for (int i = 0; i < len; ++i) {
743                         JSValue val = array->get(exec, i);
744                         int itemdist = -1;
745                         QVariant item = convertValueToQVariant(exec, val, QMetaType::Int, &itemdist, visitedObjects, recursionLimit);
746                         if (itemdist >= 0)
747                             result.append(item.value<int>());
748                         else
749                             break;
750                     }
751                     // If we didn't fail conversion
752                     if (result.count() == len) {
753                         dist = 5;
754                         ret = QVariant::fromValue(result);
755                     }
756                 } else {
757                     // Make a single length array
758                     QList<int> result;
759                     int itemdist = -1;
760                     QVariant item = convertValueToQVariant(exec, value, QMetaType::Int, &itemdist, visitedObjects, recursionLimit);
761                     if (itemdist >= 0) {
762                         result.append(item.value<int>());
763                         dist = 10;
764                         ret = QVariant::fromValue(result);
765                     }
766                 }
767                 break;
768             } else if (QtPixmapInstance::canHandle(static_cast<QMetaType::Type>(hint))) {
769                 ret = QtPixmapInstance::variantFromObject(object, static_cast<QMetaType::Type>(hint));
770             } else if (customRuntimeConversions()->contains(hint)) {
771                 ret = customRuntimeConversions()->value(hint).toVariantFunc(object, &dist, visitedObjects);
772                 if (dist == 0)
773                     break;
774             } else if (hint == (QMetaType::Type) qMetaTypeId<QVariant>()) {
775                 if (value.isUndefinedOrNull()) {
776                     if (distance)
777                         *distance = 1;
778                     return QVariant();
779                 } else {
780                     if (type == Object) {
781                         // Since we haven't really visited this object yet, we remove it
782                         visitedObjects->remove(object);
783                     }
784
785                     // And then recurse with the autodetect flag
786                     ret = convertValueToQVariant(exec, value, QMetaType::Void, distance, visitedObjects, recursionLimit);
787                     dist = 10;
788                 }
789                 break;
790             }
791
792             dist = 10;
793             break;
794     }
795
796     if (!ret.isValid())
797         dist = -1;
798     if (distance)
799         *distance = dist;
800
801     return ret;
802 }
803
804 QVariant convertValueToQVariant(ExecState* exec, JSValue value, QMetaType::Type hint, int *distance)
805 {
806     const int recursionLimit = 200;
807     HashSet<JSObject*> visitedObjects;
808     return convertValueToQVariant(exec, value, hint, distance, &visitedObjects, recursionLimit);
809 }
810
811 JSValue convertQVariantToValue(ExecState* exec, PassRefPtr<RootObject> root, const QVariant& variant)
812 {
813     // Variants with QObject * can be isNull but not a null pointer
814     // An empty QString variant is also null
815     QMetaType::Type type = (QMetaType::Type) variant.userType();
816
817     qConvDebug() << "convertQVariantToValue: metatype:" << type << ", isnull: " << variant.isNull();
818     if (variant.isNull() &&
819         type != QMetaType::QObjectStar &&
820         type != QMetaType::VoidStar &&
821         type != QMetaType::QWidgetStar &&
822         type != QMetaType::QString) {
823         return jsNull();
824     }
825
826     JSLock lock(SilenceAssertionsOnly);
827
828     if (type == QMetaType::Bool)
829         return jsBoolean(variant.toBool());
830
831     if (type == QMetaType::Int ||
832         type == QMetaType::UInt ||
833         type == QMetaType::Long ||
834         type == QMetaType::ULong ||
835         type == QMetaType::LongLong ||
836         type == QMetaType::ULongLong ||
837         type == QMetaType::Short ||
838         type == QMetaType::UShort ||
839         type == QMetaType::Float ||
840         type == QMetaType::Double)
841         return jsNumber(variant.toDouble());
842
843     if (type == QMetaType::QRegExp) {
844         QRegExp re = variant.value<QRegExp>();
845
846         if (re.isValid()) {
847             UString pattern((UChar*)re.pattern().utf16(), re.pattern().length());
848             RegExpFlags flags = (re.caseSensitivity() == Qt::CaseInsensitive) ? FlagIgnoreCase : NoFlags;
849
850             JSC::RegExp* regExp = JSC::RegExp::create(exec->globalData(), pattern, flags);
851             if (regExp->isValid())
852                 return RegExpObject::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->regExpStructure(), regExp);
853             return jsNull();
854         }
855     }
856
857     if (type == QMetaType::QDateTime ||
858         type == QMetaType::QDate ||
859         type == QMetaType::QTime) {
860
861         QDate date = QDate::currentDate();
862         QTime time(0,0,0); // midnight
863
864         if (type == QMetaType::QDate)
865             date = variant.value<QDate>();
866         else if (type == QMetaType::QTime)
867             time = variant.value<QTime>();
868         else {
869             QDateTime dt = variant.value<QDateTime>().toLocalTime();
870             date = dt.date();
871             time = dt.time();
872         }
873
874         // Dates specified this way are in local time (we convert DateTimes above)
875         GregorianDateTime dt;
876         dt.year = date.year() - 1900;
877         dt.month = date.month() - 1;
878         dt.monthDay = date.day();
879         dt.hour = time.hour();
880         dt.minute = time.minute();
881         dt.second = time.second();
882         dt.isDST = -1;
883         double ms = gregorianDateTimeToMS(exec, dt, time.msec(), /*inputIsUTC*/ false);
884
885         return DateInstance::create(exec, exec->lexicalGlobalObject()->dateStructure(), trunc(ms));
886     }
887
888     if (type == QMetaType::QByteArray) {
889         QByteArray qtByteArray = variant.value<QByteArray>();
890         WTF::RefPtr<WTF::Uint8ClampedArray> wtfByteArray = WTF::Uint8ClampedArray::createUninitialized(qtByteArray.length());
891         memcpy(wtfByteArray->data(), qtByteArray.constData(), qtByteArray.length());
892         return toJS(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), wtfByteArray.get());
893     }
894
895     if (type == QMetaType::QObjectStar || type == QMetaType::QWidgetStar) {
896         QObject* obj = variant.value<QObject*>();
897         if (!obj)
898             return jsNull();
899         return QtInstance::getQtInstance(obj, root, QScriptEngine::QtOwnership)->createRuntimeObject(exec);
900     }
901
902     if (QtPixmapInstance::canHandle(static_cast<QMetaType::Type>(variant.type())))
903         return QtPixmapInstance::createPixmapRuntimeObject(exec, root, variant);
904
905     if (customRuntimeConversions()->contains(type)) {
906         if (!root->globalObject()->inherits(&JSDOMWindow::s_info))
907             return jsUndefined();
908
909         Document* document = (static_cast<JSDOMWindow*>(root->globalObject()))->impl()->document();
910         if (!document)
911             return jsUndefined();
912         return customRuntimeConversions()->value(type).toJSValueFunc(exec, toJSDOMGlobalObject(document, exec), variant);
913     }
914
915     if (type == QMetaType::QVariantMap) {
916         // create a new object, and stuff properties into it
917         JSObject* ret = constructEmptyObject(exec);
918         QVariantMap map = variant.value<QVariantMap>();
919         QVariantMap::const_iterator i = map.constBegin();
920         while (i != map.constEnd()) {
921             QString s = i.key();
922             JSValue val = convertQVariantToValue(exec, root.get(), i.value());
923             if (val) {
924                 PutPropertySlot slot;
925                 ret->methodTable()->put(ret, exec, Identifier(&exec->globalData(), reinterpret_cast_ptr<const UChar *>(s.constData()), s.length()), val, slot);
926                 // ### error case?
927             }
928             ++i;
929         }
930
931         return ret;
932     }
933
934     // List types
935     if (type == QMetaType::QVariantList) {
936         QVariantList vl = variant.toList();
937         qConvDebug() << "got a " << vl.count() << " length list:" << vl;
938         return RuntimeArray::create(exec, new QtArray<QVariant>(vl, QMetaType::Void, root));
939     } else if (type == QMetaType::QStringList) {
940         QStringList sl = variant.value<QStringList>();
941         return RuntimeArray::create(exec, new QtArray<QString>(sl, QMetaType::QString, root));
942     } else if (type == (QMetaType::Type) qMetaTypeId<QObjectList>()) {
943         QObjectList ol= variant.value<QObjectList>();
944         return RuntimeArray::create(exec, new QtArray<QObject*>(ol, QMetaType::QObjectStar, root));
945     } else if (type == (QMetaType::Type)qMetaTypeId<QList<int> >()) {
946         QList<int> il= variant.value<QList<int> >();
947         return RuntimeArray::create(exec, new QtArray<int>(il, QMetaType::Int, root));
948     }
949
950     if (type == (QMetaType::Type)qMetaTypeId<QVariant>()) {
951         QVariant real = variant.value<QVariant>();
952         qConvDebug() << "real variant is:" << real;
953         return convertQVariantToValue(exec, root, real);
954     }
955
956     qConvDebug() << "fallback path for" << variant << variant.userType();
957
958     QString string = variant.toString();
959     UString ustring((UChar*)string.utf16(), string.length());
960     return jsString(exec, ustring);
961 }
962
963 // ===============
964
965 // Qt-like macros
966 #define QW_D(Class) Class##Data* d = d_func()
967 #define QW_DS(Class,Instance) Class##Data* d = Instance->d_func()
968
969 const ClassInfo QtRuntimeMethod::s_info = { "QtRuntimeMethod", &InternalFunction::s_info, 0, 0, CREATE_METHOD_TABLE(QtRuntimeMethod) };
970
971 QtRuntimeMethod::QtRuntimeMethod(QtRuntimeMethodData* dd, ExecState* exec, Structure* structure, const UString& identifier)
972     : InternalFunction(exec->lexicalGlobalObject(), structure)
973     , d_ptr(dd)
974 {
975 }
976
977 void QtRuntimeMethod::finishCreation(ExecState* exec, const UString& identifier, PassRefPtr<QtInstance> instance)
978 {
979     Base::finishCreation(exec->globalData(), identifier);
980     QW_D(QtRuntimeMethod);
981     d->m_instance = instance;
982     d->m_finalizer = PassWeak<QtRuntimeMethod>(this, d);
983 }
984
985 QtRuntimeMethod::~QtRuntimeMethod()
986 {
987     delete d_ptr;
988 }
989
990 void QtRuntimeMethod::destroy(JSCell* cell)
991 {
992     jsCast<QtRuntimeMethod*>(cell)->QtRuntimeMethod::~QtRuntimeMethod();
993 }
994
995 // ===============
996
997 QtRuntimeMethodData::~QtRuntimeMethodData()
998 {
999 }
1000
1001 void QtRuntimeMethodData::finalize(Handle<Unknown> value, void*)
1002 {
1003     m_instance->removeCachedMethod(static_cast<JSObject*>(value.get().asCell()));
1004 }
1005
1006 QtRuntimeMetaMethodData::~QtRuntimeMetaMethodData()
1007 {
1008
1009 }
1010
1011 QtRuntimeConnectionMethodData::~QtRuntimeConnectionMethodData()
1012 {
1013
1014 }
1015
1016 // ===============
1017
1018 // Type conversion metadata (from QtScript originally)
1019 class QtMethodMatchType
1020 {
1021 public:
1022     enum Kind {
1023         Invalid,
1024         Variant,
1025         MetaType,
1026         Unresolved,
1027         MetaEnum
1028     };
1029
1030
1031     QtMethodMatchType()
1032         : m_kind(Invalid) { }
1033
1034     Kind kind() const
1035     { return m_kind; }
1036
1037     QMetaType::Type typeId() const;
1038
1039     bool isValid() const
1040     { return (m_kind != Invalid); }
1041
1042     bool isVariant() const
1043     { return (m_kind == Variant); }
1044
1045     bool isMetaType() const
1046     { return (m_kind == MetaType); }
1047
1048     bool isUnresolved() const
1049     { return (m_kind == Unresolved); }
1050
1051     bool isMetaEnum() const
1052     { return (m_kind == MetaEnum); }
1053
1054     QByteArray name() const;
1055
1056     int enumeratorIndex() const
1057     { Q_ASSERT(isMetaEnum()); return m_typeId; }
1058
1059     static QtMethodMatchType variant()
1060     { return QtMethodMatchType(Variant); }
1061
1062     static QtMethodMatchType metaType(int typeId, const QByteArray &name)
1063     { return QtMethodMatchType(MetaType, typeId, name); }
1064
1065     static QtMethodMatchType metaEnum(int enumIndex, const QByteArray &name)
1066     { return QtMethodMatchType(MetaEnum, enumIndex, name); }
1067
1068     static QtMethodMatchType unresolved(const QByteArray &name)
1069     { return QtMethodMatchType(Unresolved, /*typeId=*/0, name); }
1070
1071 private:
1072     QtMethodMatchType(Kind kind, int typeId = 0, const QByteArray &name = QByteArray())
1073         : m_kind(kind), m_typeId(typeId), m_name(name) { }
1074
1075     Kind m_kind;
1076     int m_typeId;
1077     QByteArray m_name;
1078 };
1079
1080 QMetaType::Type QtMethodMatchType::typeId() const
1081 {
1082     if (isVariant())
1083         return (QMetaType::Type) QMetaType::type("QVariant");
1084     return (QMetaType::Type) (isMetaEnum() ? QMetaType::Int : m_typeId);
1085 }
1086
1087 QByteArray QtMethodMatchType::name() const
1088 {
1089     if (!m_name.isEmpty())
1090         return m_name;
1091     else if (m_kind == Variant)
1092         return "QVariant";
1093     return QByteArray();
1094 }
1095
1096 struct QtMethodMatchData
1097 {
1098     int matchDistance;
1099     int index;
1100     QVector<QtMethodMatchType> types;
1101     QVarLengthArray<QVariant, 10> args;
1102
1103     QtMethodMatchData(int dist, int idx, QVector<QtMethodMatchType> typs,
1104                                 const QVarLengthArray<QVariant, 10> &as)
1105         : matchDistance(dist), index(idx), types(typs), args(as) { }
1106     QtMethodMatchData()
1107         : index(-1) { }
1108
1109     bool isValid() const
1110     { return (index != -1); }
1111
1112     int firstUnresolvedIndex() const
1113     {
1114         for (int i=0; i < types.count(); i++) {
1115             if (types.at(i).isUnresolved())
1116                 return i;
1117         }
1118         return -1;
1119     }
1120 };
1121
1122 static int indexOfMetaEnum(const QMetaObject *meta, const QByteArray &str)
1123 {
1124     QByteArray scope;
1125     QByteArray name;
1126     int scopeIdx = str.indexOf("::");
1127     if (scopeIdx != -1) {
1128         scope = str.left(scopeIdx);
1129         name = str.mid(scopeIdx + 2);
1130     } else {
1131         name = str;
1132     }
1133     for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
1134         QMetaEnum m = meta->enumerator(i);
1135         if ((m.name() == name)/* && (scope.isEmpty() || (m.scope() == scope))*/)
1136             return i;
1137     }
1138     return -1;
1139 }
1140
1141 // Helper function for resolving methods
1142 // Largely based on code in QtScript for compatibility reasons
1143 static int findMethodIndex(ExecState* exec,
1144                            const QMetaObject* meta,
1145                            const QByteArray& signature,
1146                            bool allowPrivate,
1147                            QVarLengthArray<QVariant, 10> &vars,
1148                            void** vvars,
1149                            JSObject **pError)
1150 {
1151     QList<int> matchingIndices;
1152
1153     bool overloads = !signature.contains('(');
1154
1155     int count = meta->methodCount();
1156     for (int i = count - 1; i >= 0; --i) {
1157         const QMetaMethod m = meta->method(i);
1158
1159         // Don't choose private methods
1160         if (m.access() == QMetaMethod::Private && !allowPrivate)
1161             continue;
1162
1163         // try and find all matching named methods
1164         if (m.signature() == signature)
1165             matchingIndices.append(i);
1166         else if (overloads) {
1167             QByteArray rawsignature = m.signature();
1168             rawsignature.truncate(rawsignature.indexOf('('));
1169             if (rawsignature == signature)
1170                 matchingIndices.append(i);
1171         }
1172     }
1173
1174     int chosenIndex = -1;
1175     *pError = 0;
1176     QVector<QtMethodMatchType> chosenTypes;
1177
1178     QVarLengthArray<QVariant, 10> args;
1179     QVector<QtMethodMatchData> candidates;
1180     QVector<QtMethodMatchData> unresolved;
1181     QVector<int> tooFewArgs;
1182     QVector<int> conversionFailed;
1183
1184     foreach(int index, matchingIndices) {
1185         QMetaMethod method = meta->method(index);
1186
1187         QVector<QtMethodMatchType> types;
1188         bool unresolvedTypes = false;
1189
1190         // resolve return type
1191         QByteArray returnTypeName = method.typeName();
1192         int rtype = QMetaType::type(returnTypeName);
1193         if ((rtype == 0) && !returnTypeName.isEmpty()) {
1194             if (returnTypeName == "QVariant") {
1195                 types.append(QtMethodMatchType::variant());
1196             } else if (returnTypeName.endsWith('*')) {
1197                 types.append(QtMethodMatchType::metaType(QMetaType::VoidStar, returnTypeName));
1198             } else {
1199                 int enumIndex = indexOfMetaEnum(meta, returnTypeName);
1200                 if (enumIndex != -1)
1201                     types.append(QtMethodMatchType::metaEnum(enumIndex, returnTypeName));
1202                 else {
1203                     unresolvedTypes = true;
1204                     types.append(QtMethodMatchType::unresolved(returnTypeName));
1205                 }
1206             }
1207         } else {
1208             if (returnTypeName == "QVariant")
1209                 types.append(QtMethodMatchType::variant());
1210             else
1211                 types.append(QtMethodMatchType::metaType(rtype, returnTypeName));
1212         }
1213
1214         // resolve argument types
1215         QList<QByteArray> parameterTypeNames = method.parameterTypes();
1216         for (int i = 0; i < parameterTypeNames.count(); ++i) {
1217             QByteArray argTypeName = parameterTypeNames.at(i);
1218             int atype = QMetaType::type(argTypeName);
1219             if (atype == 0) {
1220                 if (argTypeName == "QVariant") {
1221                     types.append(QtMethodMatchType::variant());
1222                 } else {
1223                     int enumIndex = indexOfMetaEnum(meta, argTypeName);
1224                     if (enumIndex != -1)
1225                         types.append(QtMethodMatchType::metaEnum(enumIndex, argTypeName));
1226                     else {
1227                         unresolvedTypes = true;
1228                         types.append(QtMethodMatchType::unresolved(argTypeName));
1229                     }
1230                 }
1231             } else {
1232                 if (argTypeName == "QVariant")
1233                     types.append(QtMethodMatchType::variant());
1234                 else
1235                     types.append(QtMethodMatchType::metaType(atype, argTypeName));
1236             }
1237         }
1238
1239         // If the native method requires more arguments than what was passed from JavaScript
1240         if (exec->argumentCount() + 1 < static_cast<unsigned>(types.count())) {
1241             qMatchDebug() << "Match:too few args for" << method.signature();
1242             tooFewArgs.append(index);
1243             continue;
1244         }
1245
1246         if (unresolvedTypes) {
1247             qMatchDebug() << "Match:unresolved arg types for" << method.signature();
1248             // remember it so we can give an error message later, if necessary
1249             unresolved.append(QtMethodMatchData(/*matchDistance=*/INT_MAX, index,
1250                                                    types, QVarLengthArray<QVariant, 10>()));
1251             continue;
1252         }
1253
1254         // Now convert arguments
1255         if (args.count() != types.count())
1256             args.resize(types.count());
1257
1258         QtMethodMatchType retType = types[0];
1259         args[0] = QVariant(retType.typeId(), (void *)0); // the return value
1260
1261         bool converted = true;
1262         int matchDistance = 0;
1263         for (unsigned i = 0; converted && i + 1 < static_cast<unsigned>(types.count()); ++i) {
1264             JSValue arg = i < exec->argumentCount() ? exec->argument(i) : jsUndefined();
1265
1266             int argdistance = -1;
1267             QVariant v = convertValueToQVariant(exec, arg, types.at(i+1).typeId(), &argdistance);
1268             if (argdistance >= 0) {
1269                 matchDistance += argdistance;
1270                 args[i+1] = v;
1271             } else {
1272                 qMatchDebug() << "failed to convert argument " << i << "type" << types.at(i+1).typeId() << QMetaType::typeName(types.at(i+1).typeId());
1273                 converted = false;
1274             }
1275         }
1276
1277         qMatchDebug() << "Match: " << method.signature() << (converted ? "converted":"failed to convert") << "distance " << matchDistance;
1278
1279         if (converted) {
1280             if ((exec->argumentCount() + 1 == static_cast<unsigned>(types.count()))
1281                 && (matchDistance == 0)) {
1282                 // perfect match, use this one
1283                 chosenIndex = index;
1284                 break;
1285             } else {
1286                 QtMethodMatchData currentMatch(matchDistance, index, types, args);
1287                 if (candidates.isEmpty()) {
1288                     candidates.append(currentMatch);
1289                 } else {
1290                     QtMethodMatchData bestMatchSoFar = candidates.at(0);
1291                     if ((args.count() > bestMatchSoFar.args.count())
1292                         || ((args.count() == bestMatchSoFar.args.count())
1293                             && (matchDistance <= bestMatchSoFar.matchDistance))) {
1294                         candidates.prepend(currentMatch);
1295                     } else {
1296                         candidates.append(currentMatch);
1297                     }
1298                 }
1299             }
1300         } else {
1301             conversionFailed.append(index);
1302         }
1303
1304         if (!overloads)
1305             break;
1306     }
1307
1308     if (chosenIndex == -1 && candidates.count() == 0) {
1309         // No valid functions at all - format an error message
1310         if (!conversionFailed.isEmpty()) {
1311             QString message = QString::fromLatin1("incompatible type of argument(s) in call to %0(); candidates were\n")
1312                               .arg(QLatin1String(signature));
1313             for (int i = 0; i < conversionFailed.size(); ++i) {
1314                 if (i > 0)
1315                     message += QLatin1String("\n");
1316                 QMetaMethod mtd = meta->method(conversionFailed.at(i));
1317                 message += QString::fromLatin1("    %0").arg(QString::fromLatin1(mtd.signature()));
1318             }
1319             *pError = throwError(exec, createTypeError(exec, message.toLatin1().constData()));
1320         } else if (!unresolved.isEmpty()) {
1321             QtMethodMatchData argsInstance = unresolved.first();
1322             int unresolvedIndex = argsInstance.firstUnresolvedIndex();
1323             Q_ASSERT(unresolvedIndex != -1);
1324             QtMethodMatchType unresolvedType = argsInstance.types.at(unresolvedIndex);
1325             QString message = QString::fromLatin1("cannot call %0(): unknown type `%1'")
1326                 .arg(QString::fromLatin1(signature))
1327                 .arg(QLatin1String(unresolvedType.name()));
1328             *pError = throwError(exec, createTypeError(exec, message.toLatin1().constData()));
1329         } else {
1330             QString message = QString::fromLatin1("too few arguments in call to %0(); candidates are\n")
1331                               .arg(QLatin1String(signature));
1332             for (int i = 0; i < tooFewArgs.size(); ++i) {
1333                 if (i > 0)
1334                     message += QLatin1String("\n");
1335                 QMetaMethod mtd = meta->method(tooFewArgs.at(i));
1336                 message += QString::fromLatin1("    %0").arg(QString::fromLatin1(mtd.signature()));
1337             }
1338             *pError = throwError(exec, createSyntaxError(exec, message.toLatin1().constData()));
1339         }
1340     }
1341
1342     if (chosenIndex == -1 && candidates.count() > 0) {
1343         QtMethodMatchData bestMatch = candidates.at(0);
1344         if ((candidates.size() > 1)
1345             && (bestMatch.args.count() == candidates.at(1).args.count())
1346             && (bestMatch.matchDistance == candidates.at(1).matchDistance)) {
1347             // ambiguous call
1348             QString message = QString::fromLatin1("ambiguous call of overloaded function %0(); candidates were\n")
1349                                 .arg(QLatin1String(signature));
1350             for (int i = 0; i < candidates.size(); ++i) {
1351                 // Only candidate for overload if argument count and match distance is same as best match
1352                 if (candidates.at(i).args.count() == bestMatch.args.count()
1353                     || candidates.at(i).matchDistance == bestMatch.matchDistance) {
1354                     if (i > 0)
1355                         message += QLatin1String("\n");
1356                     QMetaMethod mtd = meta->method(candidates.at(i).index);
1357                     message += QString::fromLatin1("    %0").arg(QString::fromLatin1(mtd.signature()));
1358                 }
1359             }
1360             *pError = throwError(exec, createTypeError(exec, message.toLatin1().constData()));
1361         } else {
1362             chosenIndex = bestMatch.index;
1363             args = bestMatch.args;
1364         }
1365     }
1366
1367     if (chosenIndex != -1) {
1368         /* Copy the stuff over */
1369         int i;
1370         vars.resize(args.count());
1371         for (i=0; i < args.count(); i++) {
1372             vars[i] = args[i];
1373             vvars[i] = vars[i].data();
1374         }
1375     }
1376
1377     return chosenIndex;
1378 }
1379
1380 // Signals are not fuzzy matched as much as methods
1381 static int findSignalIndex(const QMetaObject* meta, int initialIndex, QByteArray signature)
1382 {
1383     int index = initialIndex;
1384     QMetaMethod method = meta->method(index);
1385     bool overloads = !signature.contains('(');
1386     if (overloads && (method.attributes() & QMetaMethod::Cloned)) {
1387         // find the most general method
1388         do {
1389             method = meta->method(--index);
1390         } while (method.attributes() & QMetaMethod::Cloned);
1391     }
1392     return index;
1393 }
1394
1395 const ClassInfo QtRuntimeMetaMethod::s_info = { "QtRuntimeMethod", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(QtRuntimeMetaMethod) };
1396
1397 QtRuntimeMetaMethod::QtRuntimeMetaMethod(ExecState* exec, Structure* structure, const UString& identifier)
1398     : QtRuntimeMethod (new QtRuntimeMetaMethodData(), exec, structure, identifier)
1399 {
1400 }
1401
1402 void QtRuntimeMetaMethod::finishCreation(ExecState* exec, const UString& identifier, PassRefPtr<QtInstance> instance, int index, const QByteArray& signature, bool allowPrivate)
1403 {
1404     Base::finishCreation(exec, identifier, instance);
1405     QW_D(QtRuntimeMetaMethod);
1406     d->m_signature = signature;
1407     d->m_index = index;
1408     d->m_allowPrivate = allowPrivate;
1409 }
1410
1411 void QtRuntimeMetaMethod::visitChildren(JSCell* cell, SlotVisitor& visitor)
1412 {
1413     QtRuntimeMetaMethod* thisObject = jsCast<QtRuntimeMetaMethod*>(cell);
1414     QtRuntimeMethod::visitChildren(thisObject, visitor);
1415     QtRuntimeMetaMethodData* d = thisObject->d_func();
1416     if (d->m_connect)
1417         visitor.append(&d->m_connect);
1418     if (d->m_disconnect)
1419         visitor.append(&d->m_disconnect);
1420 }
1421
1422 EncodedJSValue QtRuntimeMetaMethod::call(ExecState* exec)
1423 {
1424     QtRuntimeMetaMethodData* d = static_cast<QtRuntimeMetaMethod *>(exec->callee())->d_func();
1425
1426     // We're limited to 10 args
1427     if (exec->argumentCount() > 10)
1428         return JSValue::encode(jsUndefined());
1429
1430     // We have to pick a method that matches..
1431     JSLock lock(SilenceAssertionsOnly);
1432
1433     QObject *obj = d->m_instance->getObject();
1434     if (obj) {
1435         QVarLengthArray<QVariant, 10> vargs;
1436         void *qargs[11];
1437
1438         int methodIndex;
1439         JSObject* errorObj = 0;
1440         if ((methodIndex = findMethodIndex(exec, obj->metaObject(), d->m_signature, d->m_allowPrivate, vargs, (void **)qargs, &errorObj)) != -1) {
1441             if (QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, methodIndex, qargs) >= 0)
1442                 return JSValue::encode(jsUndefined());
1443
1444             if (vargs[0].isValid())
1445                 return JSValue::encode(convertQVariantToValue(exec, d->m_instance->rootObject(), vargs[0]));
1446         }
1447
1448         if (errorObj)
1449             return JSValue::encode(errorObj);
1450     } else {
1451         return throwVMError(exec, createError(exec, "cannot call function of deleted QObject"));
1452     }
1453
1454     // void functions return undefined
1455     return JSValue::encode(jsUndefined());
1456 }
1457
1458 CallType QtRuntimeMetaMethod::getCallData(JSCell*, CallData& callData)
1459 {
1460     callData.native.function = call;
1461     return CallTypeHost;
1462 }
1463
1464 bool QtRuntimeMetaMethod::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
1465 {
1466     QtRuntimeMetaMethod* thisObject = jsCast<QtRuntimeMetaMethod*>(cell);
1467     if (propertyName == Identifier(exec, "connect")) {
1468         slot.setCustom(thisObject, thisObject->connectGetter);
1469         return true;
1470     }
1471     if (propertyName == Identifier(exec, "disconnect")) {
1472         slot.setCustom(thisObject, thisObject->disconnectGetter);
1473         return true;
1474     }
1475     if (propertyName == exec->propertyNames().length) {
1476         slot.setCustom(thisObject, thisObject->lengthGetter);
1477         return true;
1478     }
1479
1480     return QtRuntimeMethod::getOwnPropertySlot(thisObject, exec, propertyName, slot);
1481 }
1482
1483 bool QtRuntimeMetaMethod::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
1484 {
1485     QtRuntimeMetaMethod* thisObject = jsCast<QtRuntimeMetaMethod*>(object);
1486     if (propertyName == Identifier(exec, "connect")) {
1487         PropertySlot slot;
1488         slot.setCustom(thisObject, connectGetter);
1489         descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
1490         return true;
1491     }
1492
1493     if (propertyName == Identifier(exec, "disconnect")) {
1494         PropertySlot slot;
1495         slot.setCustom(thisObject, disconnectGetter);
1496         descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
1497         return true;
1498     }
1499
1500     if (propertyName == exec->propertyNames().length) {
1501         PropertySlot slot;
1502         slot.setCustom(thisObject, lengthGetter);
1503         descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
1504         return true;
1505     }
1506
1507     return QtRuntimeMethod::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
1508 }
1509
1510 void QtRuntimeMetaMethod::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
1511 {
1512     if (mode == IncludeDontEnumProperties) {
1513         propertyNames.add(Identifier(exec, "connect"));
1514         propertyNames.add(Identifier(exec, "disconnect"));
1515         propertyNames.add(exec->propertyNames().length);
1516     }
1517
1518     QtRuntimeMethod::getOwnPropertyNames(object, exec, propertyNames, mode);
1519 }
1520
1521 JSValue QtRuntimeMetaMethod::lengthGetter(ExecState*, JSValue, PropertyName)
1522 {
1523     // QtScript always returns 0
1524     return jsNumber(0);
1525 }
1526
1527 JSValue QtRuntimeMetaMethod::connectGetter(ExecState* exec, JSValue slotBase, PropertyName ident)
1528 {
1529     QtRuntimeMetaMethod* thisObj = static_cast<QtRuntimeMetaMethod*>(asObject(slotBase));
1530     QW_DS(QtRuntimeMetaMethod, thisObj);
1531
1532     if (!d->m_connect)
1533         d->m_connect.set(exec->globalData(), thisObj, QtRuntimeConnectionMethod::create(exec, ident.ustring(), true, d->m_instance, d->m_index, d->m_signature));
1534     return d->m_connect.get();
1535 }
1536
1537 JSValue QtRuntimeMetaMethod::disconnectGetter(ExecState* exec, JSValue slotBase, PropertyName ident)
1538 {
1539     QtRuntimeMetaMethod* thisObj = static_cast<QtRuntimeMetaMethod*>(asObject(slotBase));
1540     QW_DS(QtRuntimeMetaMethod, thisObj);
1541
1542     if (!d->m_disconnect)
1543         d->m_disconnect.set(exec->globalData(), thisObj, QtRuntimeConnectionMethod::create(exec, ident.ustring(), false, d->m_instance, d->m_index, d->m_signature));
1544     return d->m_disconnect.get();
1545 }
1546
1547 // ===============
1548
1549 QMultiMap<QObject*, QtConnectionObject*> QtRuntimeConnectionMethod::connections;
1550
1551 const ClassInfo QtRuntimeConnectionMethod::s_info = { "QtRuntimeMethod", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(QtRuntimeConnectionMethod) };
1552
1553 QtRuntimeConnectionMethod::QtRuntimeConnectionMethod(ExecState* exec, Structure* structure, const UString& identifier)
1554     : QtRuntimeMethod (new QtRuntimeConnectionMethodData(), exec, structure, identifier)
1555 {
1556 }
1557
1558 void QtRuntimeConnectionMethod::finishCreation(ExecState* exec, const UString& identifier, bool isConnect, PassRefPtr<QtInstance> instance, int index, const QByteArray& signature)
1559 {
1560     Base::finishCreation(exec, identifier, instance);
1561     QW_D(QtRuntimeConnectionMethod);
1562
1563     d->m_signature = signature;
1564     d->m_index = index;
1565     d->m_isConnect = isConnect;
1566 }
1567
1568 EncodedJSValue QtRuntimeConnectionMethod::call(ExecState* exec)
1569 {
1570     QtRuntimeConnectionMethodData* d = static_cast<QtRuntimeConnectionMethod *>(exec->callee())->d_func();
1571
1572     JSLock lock(SilenceAssertionsOnly);
1573
1574     QObject* sender = d->m_instance->getObject();
1575
1576     if (sender) {
1577
1578         JSObject* thisObject = exec->lexicalGlobalObject()->methodTable()->toThisObject(exec->lexicalGlobalObject(), exec);
1579         JSObject* funcObject = 0;
1580
1581         // QtScript checks signalness first, arguments second
1582         int signalIndex = -1;
1583
1584         // Make sure the initial index is a signal
1585         QMetaMethod m = sender->metaObject()->method(d->m_index);
1586         if (m.methodType() == QMetaMethod::Signal)
1587             signalIndex = findSignalIndex(sender->metaObject(), d->m_index, d->m_signature);
1588
1589         if (signalIndex != -1) {
1590             if (exec->argumentCount() == 1) {
1591                 funcObject = exec->argument(0).toObject(exec);
1592                 CallData callData;
1593                 if (funcObject->methodTable()->getCallData(funcObject, callData) == CallTypeNone) {
1594                     if (d->m_isConnect)
1595                         return throwVMError(exec, createTypeError(exec, "QtMetaMethod.connect: target is not a function"));
1596                     else
1597                         return throwVMError(exec, createTypeError(exec, "QtMetaMethod.disconnect: target is not a function"));
1598                 }
1599             } else if (exec->argumentCount() >= 2) {
1600                 if (exec->argument(0).isObject()) {
1601                     thisObject = exec->argument(0).toObject(exec);
1602
1603                     // Get the actual function to call
1604                     JSObject *asObj = exec->argument(1).toObject(exec);
1605                     CallData callData;
1606                     if (asObj->methodTable()->getCallData(asObj, callData) != CallTypeNone) {
1607                         // Function version
1608                         funcObject = asObj;
1609                     } else {
1610                         // Convert it to a string
1611                         UString funcName = exec->argument(1).toString(exec)->value(exec);
1612                         Identifier funcIdent(exec, funcName);
1613
1614                         // ### DropAllLocks
1615                         // This is resolved at this point in QtScript
1616                         JSValue val = thisObject->get(exec, funcIdent);
1617                         JSObject* asFuncObj = val.toObject(exec);
1618
1619                         if (asFuncObj->methodTable()->getCallData(asFuncObj, callData) != CallTypeNone) {
1620                             funcObject = asFuncObj;
1621                         } else {
1622                             if (d->m_isConnect)
1623                                 return throwVMError(exec, createTypeError(exec, "QtMetaMethod.connect: target is not a function"));
1624                             else
1625                                 return throwVMError(exec, createTypeError(exec, "QtMetaMethod.disconnect: target is not a function"));
1626                         }
1627                     }
1628                 } else {
1629                     if (d->m_isConnect)
1630                         return throwVMError(exec, createTypeError(exec, "QtMetaMethod.connect: thisObject is not an object"));
1631                     else
1632                         return throwVMError(exec, createTypeError(exec, "QtMetaMethod.disconnect: thisObject is not an object"));
1633                 }
1634             } else {
1635                 if (d->m_isConnect)
1636                     return throwVMError(exec, createError(exec, "QtMetaMethod.connect: no arguments given"));
1637                 else
1638                     return throwVMError(exec, createError(exec, "QtMetaMethod.disconnect: no arguments given"));
1639             }
1640
1641             if (d->m_isConnect) {
1642                 // to connect, we need:
1643                 //  target object [from ctor]
1644                 //  target signal index etc. [from ctor]
1645                 //  receiver function [from arguments]
1646                 //  receiver this object [from arguments]
1647
1648                 ExecState* globalExec = exec->lexicalGlobalObject()->globalExec();
1649                 QtConnectionObject* conn = QtConnectionObject::createWithInternalJSC(globalExec, d->m_instance, signalIndex, thisObject, funcObject);
1650                 bool ok = QMetaObject::connect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
1651                 if (!ok) {
1652                     delete conn;
1653                     QString msg = QString(QLatin1String("QtMetaMethod.connect: failed to connect to %1::%2()"))
1654                             .arg(QLatin1String(sender->metaObject()->className()))
1655                             .arg(QLatin1String(d->m_signature));
1656                     return throwVMError(exec, createError(exec, msg.toLatin1().constData()));
1657                 }
1658                 else {
1659                     // Store connection
1660                     connections.insert(sender, conn);
1661                 }
1662             } else {
1663                 // Now to find our previous connection object. Hmm.
1664                 QList<QtConnectionObject*> conns = connections.values(sender);
1665                 bool ret = false;
1666
1667                 JSContextRef context = ::toRef(exec);
1668                 JSObjectRef receiver = ::toRef(thisObject);
1669                 JSObjectRef receiverFunction = ::toRef(funcObject);
1670
1671                 foreach(QtConnectionObject* conn, conns) {
1672                     // Is this the right connection?
1673                     if (conn->match(context, sender, signalIndex, receiver, receiverFunction)) {
1674                         // Yep, disconnect it
1675                         QMetaObject::disconnect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
1676                         delete conn; // this will also remove it from the map
1677                         ret = true;
1678                         break;
1679                     }
1680                 }
1681
1682                 if (!ret) {
1683                     QString msg = QString(QLatin1String("QtMetaMethod.disconnect: failed to disconnect from %1::%2()"))
1684                             .arg(QLatin1String(sender->metaObject()->className()))
1685                             .arg(QLatin1String(d->m_signature));
1686                     return throwVMError(exec, createError(exec, msg.toLatin1().constData()));
1687                 }
1688             }
1689         } else {
1690             QString msg = QString(QLatin1String("QtMetaMethod.%1: %2::%3() is not a signal"))
1691                     .arg(QLatin1String(d->m_isConnect ? "connect": "disconnect"))
1692                     .arg(QLatin1String(sender->metaObject()->className()))
1693                     .arg(QLatin1String(d->m_signature));
1694             return throwVMError(exec, createTypeError(exec, msg.toLatin1().constData()));
1695         }
1696     } else {
1697         return throwVMError(exec, createError(exec, "cannot call function of deleted QObject"));
1698     }
1699
1700     return JSValue::encode(jsUndefined());
1701 }
1702
1703 CallType QtRuntimeConnectionMethod::getCallData(JSCell*, CallData& callData)
1704 {
1705     callData.native.function = call;
1706     return CallTypeHost;
1707 }
1708
1709 bool QtRuntimeConnectionMethod::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
1710 {
1711     QtRuntimeConnectionMethod* thisObject = jsCast<QtRuntimeConnectionMethod*>(cell);
1712     if (propertyName == exec->propertyNames().length) {
1713         slot.setCustom(thisObject, thisObject->lengthGetter);
1714         return true;
1715     }
1716
1717     return QtRuntimeMethod::getOwnPropertySlot(thisObject, exec, propertyName, slot);
1718 }
1719
1720 bool QtRuntimeConnectionMethod::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
1721 {
1722     QtRuntimeConnectionMethod* thisObject = jsCast<QtRuntimeConnectionMethod*>(object);
1723     if (propertyName == exec->propertyNames().length) {
1724         PropertySlot slot;
1725         slot.setCustom(thisObject, lengthGetter);
1726         descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
1727         return true;
1728     }
1729
1730     return QtRuntimeMethod::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
1731 }
1732
1733 void QtRuntimeConnectionMethod::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
1734 {
1735     if (mode == IncludeDontEnumProperties)
1736         propertyNames.add(exec->propertyNames().length);
1737
1738     QtRuntimeMethod::getOwnPropertyNames(object, exec, propertyNames, mode);
1739 }
1740
1741 JSValue QtRuntimeConnectionMethod::lengthGetter(ExecState*, JSValue, PropertyName)
1742 {
1743     // we have one formal argument, and one optional
1744     return jsNumber(1);
1745 }
1746
1747 // ===============
1748
1749 QtConnectionObject::QtConnectionObject(JSContextRef context, PassRefPtr<QtInstance> senderInstance, int signalIndex, JSObjectRef receiver, JSObjectRef receiverFunction)
1750     : QObject(senderInstance->getObject())
1751     , m_context(context)
1752     , m_senderInstance(senderInstance)
1753     , m_originalSender(m_senderInstance->getObject())
1754     , m_signalIndex(signalIndex)
1755     , m_receiver(receiver)
1756     , m_receiverFunction(receiverFunction)
1757 {
1758     JSValueProtect(m_context, m_receiver);
1759     JSValueProtect(m_context, m_receiverFunction);
1760 }
1761
1762 QtConnectionObject::~QtConnectionObject()
1763 {
1764     // We can safely use m_originalSender because connection object will never outlive the sender,
1765     // which is its QObject parent.
1766     QtRuntimeConnectionMethod::connections.remove(m_originalSender, this);
1767
1768     JSValueUnprotect(m_context, m_receiver);
1769     JSValueUnprotect(m_context, m_receiverFunction);
1770 }
1771
1772 static const uint qt_meta_data_QtConnectionObject[] = {
1773
1774  // content:
1775        1,       // revision
1776        0,       // classname
1777        0,    0, // classinfo
1778        1,   10, // methods
1779        0,    0, // properties
1780        0,    0, // enums/sets
1781
1782  // slots: signature, parameters, type, tag, flags
1783       28,   27,   27,   27, 0x0a,
1784
1785        0        // eod
1786 };
1787
1788 static const char qt_meta_stringdata_QtConnectionObject[] = {
1789     "JSC::Bindings::QtConnectionObject\0\0execute()\0"
1790 };
1791
1792 const QMetaObject QtConnectionObject::staticMetaObject = {
1793     { &QObject::staticMetaObject, qt_meta_stringdata_QtConnectionObject,
1794       qt_meta_data_QtConnectionObject, 0 }
1795 };
1796
1797 const QMetaObject *QtConnectionObject::metaObject() const
1798 {
1799     return &staticMetaObject;
1800 }
1801
1802 void *QtConnectionObject::qt_metacast(const char *_clname)
1803 {
1804     if (!_clname) return 0;
1805     if (!strcmp(_clname, qt_meta_stringdata_QtConnectionObject))
1806         return static_cast<void*>(const_cast<QtConnectionObject*>(this));
1807     return QObject::qt_metacast(_clname);
1808 }
1809
1810 // This is what moc would generate except by the fact that we pass all arguments to our execute() slot.
1811 int QtConnectionObject::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
1812 {
1813     _id = QObject::qt_metacall(_c, _id, _a);
1814     if (_id < 0)
1815         return _id;
1816     if (_c == QMetaObject::InvokeMetaMethod) {
1817         switch (_id) {
1818         case 0: execute(_a); break;
1819         }
1820         _id -= 1;
1821     }
1822     return _id;
1823 }
1824
1825 static bool isJavaScriptFunction(JSObjectRef object)
1826 {
1827     CallData callData;
1828     JSObject* jsObject = toJS(object);
1829     return jsObject->methodTable()->getCallData(jsObject, callData) == CallTypeJS;
1830 }
1831
1832 void QtConnectionObject::execute(void** argv)
1833 {
1834     QObject* sender = m_senderInstance->getObject();
1835     if (!sender) {
1836         qWarning() << "sender deleted, cannot deliver signal";
1837         return;
1838     }
1839
1840     ASSERT(sender == m_originalSender);
1841
1842     const QMetaObject* meta = sender->metaObject();
1843     const QMetaMethod method = meta->method(m_signalIndex);
1844
1845     QList<QByteArray> parameterTypes = method.parameterTypes();
1846
1847     JSValueRef* ignoredException = 0;
1848     JSRetainPtr<JSStringRef> lengthProperty(JSStringCreateWithUTF8CString("length"));
1849     int receiverLength = int(JSValueToNumber(m_context, JSObjectGetProperty(m_context, m_receiverFunction, lengthProperty.get(), ignoredException), ignoredException));
1850     int argc = qMax(parameterTypes.count(), receiverLength);
1851     WTF::Vector<JSValueRef> args(argc);
1852
1853     // TODO: remove once conversion functions use JSC API.
1854     ExecState* exec = ::toJS(m_context);
1855     RefPtr<RootObject> rootObject = m_senderInstance->rootObject();
1856
1857     for (int i = 0; i < argc; i++) {
1858         int argType = QMetaType::type(parameterTypes.at(i));
1859         args[i] = ::toRef(exec, convertQVariantToValue(exec, rootObject, QVariant(argType, argv[i+1])));
1860     }
1861
1862     const bool updateQtSender = isJavaScriptFunction(m_receiverFunction);
1863     if (updateQtSender)
1864         QtInstance::qtSenderStack()->push(QObject::sender());
1865
1866     JSObjectCallAsFunction(m_context, m_receiverFunction, m_receiver, argc, args.data(), 0);
1867
1868     if (updateQtSender)
1869         QtInstance::qtSenderStack()->pop();
1870 }
1871
1872 bool QtConnectionObject::match(JSContextRef context, QObject* sender, int signalIndex, JSObjectRef receiver, JSObjectRef receiverFunction)
1873 {
1874     if (sender != m_originalSender || signalIndex != m_signalIndex)
1875         return false;
1876     JSValueRef* ignoredException = 0;
1877     const bool receiverMatch = (!receiver && !m_receiver) || JSValueIsEqual(context, receiver, m_receiver, ignoredException);
1878     return receiverMatch && JSValueIsEqual(context, receiverFunction, m_receiverFunction, ignoredException);
1879 }
1880
1881 QtConnectionObject* QtConnectionObject::createWithInternalJSC(ExecState* exec, PassRefPtr<QtInstance> senderInstance, int signalIndex, JSObject* receiver, JSObject* receiverFunction)
1882 {
1883     return new QtConnectionObject(::toRef(exec), senderInstance, signalIndex, ::toRef(receiver), ::toRef(receiverFunction));
1884 }
1885
1886 // ===============
1887
1888 template <typename T> QtArray<T>::QtArray(QList<T> list, QMetaType::Type type, PassRefPtr<RootObject> rootObject)
1889     : Array(rootObject)
1890     , m_list(list)
1891     , m_type(type)
1892 {
1893     m_length = m_list.count();
1894 }
1895
1896 template <typename T> QtArray<T>::~QtArray ()
1897 {
1898 }
1899
1900 template <typename T> RootObject* QtArray<T>::rootObject() const
1901 {
1902     return m_rootObject && m_rootObject->isValid() ? m_rootObject.get() : 0;
1903 }
1904
1905 template <typename T> void QtArray<T>::setValueAt(ExecState* exec, unsigned index, JSValue aValue) const
1906 {
1907     // QtScript sets the value, but doesn't forward it to the original source
1908     // (e.g. if you do 'object.intList[5] = 6', the object is not updated, but the
1909     // copy of the list is).
1910     int dist = -1;
1911     QVariant val = convertValueToQVariant(exec, aValue, m_type, &dist);
1912
1913     if (dist >= 0) {
1914         m_list[index] = val.value<T>();
1915     }
1916 }
1917
1918
1919 template <typename T> JSValue QtArray<T>::valueAt(ExecState *exec, unsigned int index) const
1920 {
1921     if (index < m_length) {
1922         T val = m_list.at(index);
1923         return convertQVariantToValue(exec, rootObject(), QVariant::fromValue(val));
1924     }
1925
1926     return jsUndefined();
1927 }
1928
1929 // ===============
1930
1931 } }