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