Home | History | Annotate | Download | only in qt
      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:
     71     inline QWKNoDebug(){}
     72     inline ~QWKNoDebug(){}
     73 
     74     template<typename 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)
    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 
    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 
    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 
    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 
    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 
    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 
    921 QtRuntimeMethod::~QtRuntimeMethod()
    922 {
    923     QW_D(QtRuntimeMethod);
    924     d->m_instance->removeCachedMethod(this);
    925     delete d_ptr;
    926 }
    927 
    928 // ===============
    929 
    930 QtRuntimeMethodData::~QtRuntimeMethodData()
    931 {
    932 }
    933 
    934 QtRuntimeMetaMethodData::~QtRuntimeMetaMethodData()
    935 {
    936 
    937 }
    938 
    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 
    959     QtMethodMatchType()
    960         : m_kind(Invalid) { }
    961 
    962     Kind kind() const
    963     { return m_kind; }
    964 
    965     QMetaType::Type typeId() const;
    966 
    967     bool isValid() const
    968     { return (m_kind != Invalid); }
    969 
    970     bool isVariant() const
    971     { return (m_kind == Variant); }
    972 
    973     bool isMetaType() const
    974     { return (m_kind == MetaType); }
    975 
    976     bool isUnresolved() const
    977     { return (m_kind == Unresolved); }
    978 
    979     bool isMetaEnum() const
    980     { return (m_kind == MetaEnum); }
    981 
    982     QByteArray name() const;
    983 
    984     int enumeratorIndex() const
    985     { Q_ASSERT(isMetaEnum()); return m_typeId; }
    986 
    987     static QtMethodMatchType variant()
    988     { return QtMethodMatchType(Variant); }
    989 
    990     static QtMethodMatchType metaType(int typeId, const QByteArray &name)
    991     { return QtMethodMatchType(MetaType, typeId, name); }
    992 
    993     static QtMethodMatchType metaEnum(int enumIndex, const QByteArray &name)
    994     { return QtMethodMatchType(MetaEnum, enumIndex, name); }
    995 
    996     static QtMethodMatchType unresolved(const QByteArray &name)
    997     { return QtMethodMatchType(Unresolved, /*typeId=*/0, name); }
    998 
    999 private:
   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 
   1008 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 
   1015 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 
   1031     QtMethodMatchData(int dist, int idx, QVector<QtMethodMatchType> typs,
   1032                                 const QVarLengthArray<QVariant, 10> &as)
   1033         : matchDistance(dist), index(idx), types(typs), args(as) { }
   1034     QtMethodMatchData()
   1035         : index(-1) { }
   1036 
   1037     bool isValid() const
   1038     { return (index != -1); }
   1039 
   1040     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 
   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
   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
   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 
   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 
   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 
   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 
   1381 CallType QtRuntimeMetaMethod::getCallData(CallData& callData)
   1382 {
   1383     callData.native.function = call;
   1384     return CallTypeHost;
   1385 }
   1386 
   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 
   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 
   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 
   1440 JSValue QtRuntimeMetaMethod::lengthGetter(ExecState* exec, const Identifier&, const PropertySlot&)
   1441 {
   1442     // QtScript always returns 0
   1443     return jsNumber(exec, 0);
   1444 }
   1445 
   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 
   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 
   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 
   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 
   1610 CallType QtRuntimeConnectionMethod::getCallData(CallData& callData)
   1611 {
   1612     callData.native.function = call;
   1613     return CallTypeHost;
   1614 }
   1615 
   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 
   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 
   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 
   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 
   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 
   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 
   1696 const QMetaObject *QtConnectionObject::metaObject() const
   1697 {
   1698     return &staticMetaObject;
   1699 }
   1700 
   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 
   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 
   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 
   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 
   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 
   1803 template <typename T> QtArray<T>::~QtArray ()
   1804 {
   1805 }
   1806 
   1807 template <typename T> RootObject* QtArray<T>::rootObject() const
   1808 {
   1809     return m_rootObject && m_rootObject->isValid() ? m_rootObject.get() : 0;
   1810 }
   1811 
   1812 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 
   1826 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