qt_runtime.cpp 70.3 KB
Newer Older
andersca@apple.com's avatar
andersca@apple.com committed
1
/*
2
 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
andersca@apple.com's avatar
andersca@apple.com committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#include "config.h"
#include "qt_runtime.h"
22

mrowe@apple.com's avatar
mrowe@apple.com committed
23
#include "BooleanObject.h"
24
25
26
#include "DateInstance.h"
#include "DateMath.h"
#include "DatePrototype.h"
27
#include "DumpRenderTreeSupportQt.h"
28
#include "FunctionPrototype.h"
hausmann@webkit.org's avatar
hausmann@webkit.org committed
29
#include "Interpreter.h"
30
#include "JSArray.h"
hausmann@webkit.org's avatar
hausmann@webkit.org committed
31
#include "JSByteArray.h"
32
#include "JSDocument.h"
33
#include "JSDOMBinding.h"
34
35
#include "JSDOMWindow.h"
#include <JSFunction.h>
36
#include "JSGlobalObject.h"
37
#include "JSHTMLElement.h"
ap@webkit.org's avatar
ap@webkit.org committed
38
#include "JSLock.h"
darin@apple.com's avatar
darin@apple.com committed
39
#include "JSObject.h"
40
#include "ObjectPrototype.h"
41
#include "PropertyNameArray.h"
42
#include "RegExpConstructor.h"
darin@apple.com's avatar
darin@apple.com committed
43
#include "RegExpObject.h"
44
45
#include "qdatetime.h"
#include "qdebug.h"
andersca@apple.com's avatar
andersca@apple.com committed
46
#include "qmetaobject.h"
47
#include "qmetatype.h"
andersca@apple.com's avatar
andersca@apple.com committed
48
49
#include "qobject.h"
#include "qstringlist.h"
50
#include "qt_instance.h"
51
#include "qt_pixmapruntime.h"
andersca@apple.com's avatar
andersca@apple.com committed
52
#include "qvarlengtharray.h"
53
#include "qwebelement.h"
andersca@apple.com's avatar
andersca@apple.com committed
54
#include <limits.h>
mrowe@apple.com's avatar
mrowe@apple.com committed
55
#include <runtime/Error.h>
56
57
#include <runtime_array.h>
#include <runtime_object.h>
andersca@apple.com's avatar
andersca@apple.com committed
58
59
60
61
62
63

// QtScript has these
Q_DECLARE_METATYPE(QObjectList);
Q_DECLARE_METATYPE(QList<int>);
Q_DECLARE_METATYPE(QVariant);

64
using namespace WebCore;
andersca@apple.com's avatar
andersca@apple.com committed
65

66
namespace JSC {
andersca@apple.com's avatar
andersca@apple.com committed
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
namespace Bindings {

// Debugging
//#define QTWK_RUNTIME_CONVERSION_DEBUG
//#define QTWK_RUNTIME_MATCH_DEBUG

class QWKNoDebug
{
public:
    inline QWKNoDebug(){}
    inline ~QWKNoDebug(){}

    template<typename T>
    inline QWKNoDebug &operator<<(const T &) { return *this; }
};

#ifdef QTWK_RUNTIME_CONVERSION_DEBUG
#define qConvDebug() qDebug()
#else
#define qConvDebug() QWKNoDebug()
#endif

#ifdef QTWK_RUNTIME_MATCH_DEBUG
#define qMatchDebug() qDebug()
#else
#define qMatchDebug() QWKNoDebug()
#endif

typedef enum {
96
    Variant = 0,
andersca@apple.com's avatar
andersca@apple.com committed
97
98
99
100
101
102
103
104
    Number,
    Boolean,
    String,
    Date,
    RegExp,
    Array,
    QObj,
    Object,
105
    Null,
hausmann@webkit.org's avatar
hausmann@webkit.org committed
106
107
    RTArray,
    JSByteArray
andersca@apple.com's avatar
andersca@apple.com committed
108
109
} JSRealType;

110
111
112
113
114
115
116
117
118
119
120
121
#if defined(QTWK_RUNTIME_CONVERSION_DEBUG) || defined(QTWK_RUNTIME_MATCH_DEBUG)
QDebug operator<<(QDebug dbg, const JSRealType &c)
{
     const char *map[] = { "Variant", "Number", "Boolean", "String", "Date",
         "RegExp", "Array", "RTObject", "Object", "Null", "RTArray"};

     dbg.nospace() << "JSType(" << ((int)c) << ", " <<  map[c] << ")";

     return dbg.space();
}
#endif

122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// this is here as a proxy, so we'd have a class to friend in QWebElement,
// as getting/setting a WebCore in QWebElement is private
class QtWebElementRuntime {
public:
    static QWebElement create(Element* element)
    {
        return QWebElement(element);
    }

    static Element* get(const QWebElement& element)
    {
        return element.m_element;
    }
};

137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// this is here as a proxy, so we'd have a class to friend in QDRTNode,
// as getting/setting a WebCore in QDRTNode is private.
// We only need to pass WebCore Nodes for layout tests.
class QtDRTNodeRuntime {
public:
    static QDRTNode create(Node* node)
    {
        return QDRTNode(node);
    }

    static Node* get(const QDRTNode& node)
    {
        return node.m_node;
    }
};

ggaren@apple.com's avatar
ggaren@apple.com committed
153
static JSRealType valueRealType(ExecState* exec, JSValue val)
andersca@apple.com's avatar
andersca@apple.com committed
154
{
155
    if (val.isNumber())
andersca@apple.com's avatar
andersca@apple.com committed
156
        return Number;
157
    else if (val.isString())
andersca@apple.com's avatar
andersca@apple.com committed
158
        return String;
159
    else if (val.isBoolean())
andersca@apple.com's avatar
andersca@apple.com committed
160
        return Boolean;
161
    else if (val.isNull())
andersca@apple.com's avatar
andersca@apple.com committed
162
        return Null;
163
    else if (isJSByteArray(&exec->globalData(), val))
hausmann@webkit.org's avatar
hausmann@webkit.org committed
164
        return JSByteArray;
165
166
    else if (val.isObject()) {
        JSObject *object = val.toObject(exec);
167
168
        if (object->inherits(&RuntimeArray::s_info))  // RuntimeArray 'inherits' from Array, but not in C++
            return RTArray;
169
        else if (object->inherits(&JSArray::s_info))
andersca@apple.com's avatar
andersca@apple.com committed
170
            return Array;
171
        else if (object->inherits(&DateInstance::s_info))
andersca@apple.com's avatar
andersca@apple.com committed
172
            return Date;
173
        else if (object->inherits(&RegExpObject::s_info))
andersca@apple.com's avatar
andersca@apple.com committed
174
            return RegExp;
175
        else if (object->inherits(&RuntimeObject::s_info))
andersca@apple.com's avatar
andersca@apple.com committed
176
177
178
179
180
181
182
            return QObj;
        return Object;
    }

    return String; // I don't know.
}

183
QVariant convertValueToQVariant(ExecState* exec, JSValue value, QMetaType::Type hint, int *distance, HashSet<JSObject*>* visitedObjects, int recursionLimit)
andersca@apple.com's avatar
andersca@apple.com committed
184
{
185
186
187
    --recursionLimit;

    if (!value || !recursionLimit)
188
189
        return QVariant();

190
    JSObject* object = 0;
191
192
    if (value.isObject()) {
        object = value.toObject(exec);
193
194
195
196
197
198
        if (visitedObjects->contains(object))
            return QVariant();

        visitedObjects->add(object);
    }

andersca@apple.com's avatar
andersca@apple.com committed
199
    // check magic pointer values before dereferencing value
200
    if (value == jsNaN()
201
202
203
        || (value == jsUndefined()
            && hint != QMetaType::QString
            && hint != (QMetaType::Type) qMetaTypeId<QVariant>())) {
andersca@apple.com's avatar
andersca@apple.com committed
204
205
206
207
208
        if (distance)
            *distance = -1;
        return QVariant();
    }

ap@webkit.org's avatar
ap@webkit.org committed
209
    JSLock lock(SilenceAssertionsOnly);
andersca@apple.com's avatar
andersca@apple.com committed
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
    JSRealType type = valueRealType(exec, value);
    if (hint == QMetaType::Void) {
        switch(type) {
            case Number:
                hint = QMetaType::Double;
                break;
            case Boolean:
                hint = QMetaType::Bool;
                break;
            case String:
            default:
                hint = QMetaType::QString;
                break;
            case Date:
                hint = QMetaType::QDateTime;
                break;
            case RegExp:
                hint = QMetaType::QRegExp;
                break;
229
            case Object:
230
                if (object->inherits(&NumberObject::s_info))
231
                    hint = QMetaType::Double;
232
                else if (object->inherits(&BooleanObject::s_info))
233
234
235
                    hint = QMetaType::Bool;
                else
                    hint = QMetaType::QVariantMap;
236
                break;
andersca@apple.com's avatar
andersca@apple.com committed
237
238
239
            case QObj:
                hint = QMetaType::QObjectStar;
                break;
hausmann@webkit.org's avatar
hausmann@webkit.org committed
240
241
242
            case JSByteArray:
                hint = QMetaType::QByteArray;
                break;
andersca@apple.com's avatar
andersca@apple.com committed
243
            case Array:
244
            case RTArray:
andersca@apple.com's avatar
andersca@apple.com committed
245
246
247
248
249
                hint = QMetaType::QVariantList;
                break;
        }
    }

250
251
252
    qConvDebug() << "convertValueToQVariant: jstype is " << type << ", hint is" << hint;

    if (value == jsNull()
andersca@apple.com's avatar
andersca@apple.com committed
253
        && hint != QMetaType::QObjectStar
254
255
256
        && hint != QMetaType::VoidStar
        && hint != QMetaType::QString
        && hint != (QMetaType::Type) qMetaTypeId<QVariant>()) {
andersca@apple.com's avatar
andersca@apple.com committed
257
258
259
260
261
262
263
264
265
        if (distance)
            *distance = -1;
        return QVariant();
    }

    QVariant ret;
    int dist = -1;
    switch (hint) {
        case QMetaType::Bool:
266
            if (type == Object && object->inherits(&BooleanObject::s_info))
267
                ret = QVariant(asBooleanObject(value)->internalValue().toBoolean(exec));
268
            else
269
                ret = QVariant(value.toBoolean(exec));
andersca@apple.com's avatar
andersca@apple.com committed
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
            if (type == Boolean)
                dist = 0;
            else
                dist = 10;
            break;

        case QMetaType::Int:
        case QMetaType::UInt:
        case QMetaType::Long:
        case QMetaType::ULong:
        case QMetaType::LongLong:
        case QMetaType::ULongLong:
        case QMetaType::Short:
        case QMetaType::UShort:
        case QMetaType::Float:
        case QMetaType::Double:
286
            ret = QVariant(value.toNumber(exec));
andersca@apple.com's avatar
andersca@apple.com committed
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
            ret.convert((QVariant::Type)hint);
            if (type == Number) {
                switch (hint) {
                case QMetaType::Double:
                    dist = 0;
                    break;
                case QMetaType::Float:
                    dist = 1;
                    break;
                case QMetaType::LongLong:
                case QMetaType::ULongLong:
                    dist = 2;
                    break;
                case QMetaType::Long:
                case QMetaType::ULong:
                    dist = 3;
                    break;
                case QMetaType::Int:
                case QMetaType::UInt:
                    dist = 4;
                    break;
                case QMetaType::Short:
                case QMetaType::UShort:
                    dist = 5;
                    break;
                    break;
                default:
                    dist = 10;
                    break;
                }
            } else {
                dist = 10;
            }
            break;

        case QMetaType::QChar:
            if (type == Number || type == Boolean) {
324
                ret = QVariant(QChar((ushort)value.toNumber(exec)));
andersca@apple.com's avatar
andersca@apple.com committed
325
326
327
328
329
                if (type == Boolean)
                    dist = 3;
                else
                    dist = 6;
            } else {
330
                UString str = value.toString(exec);
barraclough@apple.com's avatar
barraclough@apple.com committed
331
                ret = QVariant(QChar(str.length() ? *(const ushort*)str.impl()->characters() : 0));
andersca@apple.com's avatar
andersca@apple.com committed
332
333
334
335
336
337
338
339
                if (type == String)
                    dist = 3;
                else
                    dist = 10;
            }
            break;

        case QMetaType::QString: {
340
            if (value.isUndefinedOrNull()) {
341
342
343
344
                if (distance)
                    *distance = 1;
                return QString();
            } else {
345
                UString ustring = value.toString(exec);
barraclough@apple.com's avatar
barraclough@apple.com committed
346
                ret = QVariant(QString((const QChar*)ustring.impl()->characters(), ustring.length()));
347
348
349
350
351
                if (type == String)
                    dist = 0;
                else
                    dist = 10;
            }
andersca@apple.com's avatar
andersca@apple.com committed
352
353
354
            break;
        }

355
        case QMetaType::QVariantMap:
356
            if (type == Object || type == Array || type == RTArray) {
andersca@apple.com's avatar
andersca@apple.com committed
357
                // Enumerate the contents of the object
358
                PropertyNameArray properties(exec);
359
                object->getPropertyNames(exec, properties);
andersca@apple.com's avatar
andersca@apple.com committed
360
361
362
363
364
365
                PropertyNameArray::const_iterator it = properties.begin();

                QVariantMap result;
                int objdist = 0;
                while(it != properties.end()) {
                    if (object->propertyIsEnumerable(exec, *it)) {
ggaren@apple.com's avatar
ggaren@apple.com committed
366
                        JSValue val = object->get(exec, *it);
367
                        QVariant v = convertValueToQVariant(exec, val, QMetaType::Void, &objdist, visitedObjects, recursionLimit);
andersca@apple.com's avatar
andersca@apple.com committed
368
369
                        if (objdist >= 0) {
                            UString ustring = (*it).ustring();
barraclough@apple.com's avatar
barraclough@apple.com committed
370
                            QString id = QString((const QChar*)ustring.impl()->characters(), ustring.length());
andersca@apple.com's avatar
andersca@apple.com committed
371
372
373
374
375
376
377
378
379
380
381
                            result.insert(id, v);
                        }
                    }
                    ++it;
                }
                dist = 1;
                ret = QVariant(result);
            }
            break;

        case QMetaType::QVariantList:
382
383
384
385
386
387
388
389
            if (type == RTArray) {
                RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);

                QVariantList result;
                int len = rtarray->getLength();
                int objdist = 0;
                qConvDebug() << "converting a " << len << " length Array";
                for (int i = 0; i < len; ++i) {
ggaren@apple.com's avatar
ggaren@apple.com committed
390
                    JSValue val = rtarray->getConcreteArray()->valueAt(exec, i);
391
                    result.append(convertValueToQVariant(exec, val, QMetaType::Void, &objdist, visitedObjects, recursionLimit));
392
393
394
395
396
397
398
399
400
401
                    if (objdist == -1) {
                        qConvDebug() << "Failed converting element at index " << i;
                        break; // Failed converting a list entry, so fail the array
                    }
                }
                if (objdist != -1) {
                    dist = 5;
                    ret = QVariant(result);
                }
            } else if (type == Array) {
darin@apple.com's avatar
darin@apple.com committed
402
                JSArray* array = static_cast<JSArray*>(object);
andersca@apple.com's avatar
andersca@apple.com committed
403
404

                QVariantList result;
405
                int len = array->length();
andersca@apple.com's avatar
andersca@apple.com committed
406
                int objdist = 0;
407
                qConvDebug() << "converting a " << len << " length Array";
andersca@apple.com's avatar
andersca@apple.com committed
408
                for (int i = 0; i < len; ++i) {
ggaren@apple.com's avatar
ggaren@apple.com committed
409
                    JSValue val = array->get(exec, i);
410
                    result.append(convertValueToQVariant(exec, val, QMetaType::Void, &objdist, visitedObjects, recursionLimit));
411
412
                    if (objdist == -1) {
                        qConvDebug() << "Failed converting element at index " << i;
andersca@apple.com's avatar
andersca@apple.com committed
413
                        break; // Failed converting a list entry, so fail the array
414
                    }
andersca@apple.com's avatar
andersca@apple.com committed
415
416
417
418
419
420
421
422
                }
                if (objdist != -1) {
                    dist = 5;
                    ret = QVariant(result);
                }
            } else {
                // Make a single length array
                int objdist;
423
                qConvDebug() << "making a single length variantlist";
424
                QVariant var = convertValueToQVariant(exec, value, QMetaType::Void, &objdist, visitedObjects, recursionLimit);
andersca@apple.com's avatar
andersca@apple.com committed
425
                if (objdist != -1) {
426
427
                    QVariantList result;
                    result << var;
andersca@apple.com's avatar
andersca@apple.com committed
428
429
                    ret = QVariant(result);
                    dist = 10;
430
431
                } else {
                    qConvDebug() << "failed making single length varlist";
andersca@apple.com's avatar
andersca@apple.com committed
432
433
434
435
436
                }
            }
            break;

        case QMetaType::QStringList: {
437
438
439
440
441
442
            if (type == RTArray) {
                RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);

                QStringList result;
                int len = rtarray->getLength();
                for (int i = 0; i < len; ++i) {
ggaren@apple.com's avatar
ggaren@apple.com committed
443
                    JSValue val = rtarray->getConcreteArray()->valueAt(exec, i);
444
                    UString ustring = val.toString(exec);
barraclough@apple.com's avatar
barraclough@apple.com committed
445
                    QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
446
447
448
449
450
451

                    result.append(qstring);
                }
                dist = 5;
                ret = QVariant(result);
            } else if (type == Array) {
darin@apple.com's avatar
darin@apple.com committed
452
                JSArray* array = static_cast<JSArray*>(object);
andersca@apple.com's avatar
andersca@apple.com committed
453
454

                QStringList result;
455
                int len = array->length();
andersca@apple.com's avatar
andersca@apple.com committed
456
                for (int i = 0; i < len; ++i) {
ggaren@apple.com's avatar
ggaren@apple.com committed
457
                    JSValue val = array->get(exec, i);
458
                    UString ustring = val.toString(exec);
barraclough@apple.com's avatar
barraclough@apple.com committed
459
                    QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
andersca@apple.com's avatar
andersca@apple.com committed
460
461
462
463
464
465
466

                    result.append(qstring);
                }
                dist = 5;
                ret = QVariant(result);
            } else {
                // Make a single length array
467
                UString ustring = value.toString(exec);
barraclough@apple.com's avatar
barraclough@apple.com committed
468
                QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
andersca@apple.com's avatar
andersca@apple.com committed
469
470
471
472
473
474
475
476
477
                QStringList result;
                result.append(qstring);
                ret = QVariant(result);
                dist = 10;
            }
            break;
        }

        case QMetaType::QByteArray: {
hausmann@webkit.org's avatar
hausmann@webkit.org committed
478
479
480
481
482
483
            if (type == JSByteArray) {
                WTF::ByteArray* arr = asByteArray(value)->storage();
                ret = QVariant(QByteArray(reinterpret_cast<const char*>(arr->data()), arr->length()));
                dist = 0;
            } else {
                UString ustring = value.toString(exec);
barraclough@apple.com's avatar
barraclough@apple.com committed
484
                ret = QVariant(QString((const QChar*)ustring.impl()->characters(), ustring.length()).toLatin1());
hausmann@webkit.org's avatar
hausmann@webkit.org committed
485
486
487
488
489
                if (type == String)
                    dist = 5;
                else
                    dist = 10;
            }
andersca@apple.com's avatar
andersca@apple.com committed
490
491
492
493
494
495
496
497
            break;
        }

        case QMetaType::QDateTime:
        case QMetaType::QDate:
        case QMetaType::QTime:
            if (type == Date) {
                DateInstance* date = static_cast<DateInstance*>(object);
498
                GregorianDateTime gdt;
499
                msToGregorianDateTime(exec, date->internalNumber(), true, gdt);
andersca@apple.com's avatar
andersca@apple.com committed
500
501
502
503
504
505
506
507
508
509
510
                if (hint == QMetaType::QDateTime) {
                    ret = QDateTime(QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay), QTime(gdt.hour, gdt.minute, gdt.second), Qt::UTC);
                    dist = 0;
                } else if (hint == QMetaType::QDate) {
                    ret = QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay);
                    dist = 1;
                } else {
                    ret = QTime(gdt.hour + 1900, gdt.minute, gdt.second);
                    dist = 2;
                }
            } else if (type == Number) {
511
                double b = value.toNumber(exec);
512
                GregorianDateTime gdt;
513
                msToGregorianDateTime(exec, b, true, gdt);
andersca@apple.com's avatar
andersca@apple.com committed
514
515
516
517
518
519
520
521
522
523
                if (hint == QMetaType::QDateTime) {
                    ret = QDateTime(QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay), QTime(gdt.hour, gdt.minute, gdt.second), Qt::UTC);
                    dist = 6;
                } else if (hint == QMetaType::QDate) {
                    ret = QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay);
                    dist = 8;
                } else {
                    ret = QTime(gdt.hour, gdt.minute, gdt.second);
                    dist = 10;
                }
524
#ifndef QT_NO_DATESTRING
andersca@apple.com's avatar
andersca@apple.com committed
525
            } else if (type == String) {
526
                UString ustring = value.toString(exec);
barraclough@apple.com's avatar
barraclough@apple.com committed
527
                QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
andersca@apple.com's avatar
andersca@apple.com committed
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565

                if (hint == QMetaType::QDateTime) {
                    QDateTime dt = QDateTime::fromString(qstring, Qt::ISODate);
                    if (!dt.isValid())
                        dt = QDateTime::fromString(qstring, Qt::TextDate);
                    if (!dt.isValid())
                        dt = QDateTime::fromString(qstring, Qt::SystemLocaleDate);
                    if (!dt.isValid())
                        dt = QDateTime::fromString(qstring, Qt::LocaleDate);
                    if (dt.isValid()) {
                        ret = dt;
                        dist = 2;
                    }
                } else if (hint == QMetaType::QDate) {
                    QDate dt = QDate::fromString(qstring, Qt::ISODate);
                    if (!dt.isValid())
                        dt = QDate::fromString(qstring, Qt::TextDate);
                    if (!dt.isValid())
                        dt = QDate::fromString(qstring, Qt::SystemLocaleDate);
                    if (!dt.isValid())
                        dt = QDate::fromString(qstring, Qt::LocaleDate);
                    if (dt.isValid()) {
                        ret = dt;
                        dist = 3;
                    }
                } else {
                    QTime dt = QTime::fromString(qstring, Qt::ISODate);
                    if (!dt.isValid())
                        dt = QTime::fromString(qstring, Qt::TextDate);
                    if (!dt.isValid())
                        dt = QTime::fromString(qstring, Qt::SystemLocaleDate);
                    if (!dt.isValid())
                        dt = QTime::fromString(qstring, Qt::LocaleDate);
                    if (dt.isValid()) {
                        ret = dt;
                        dist = 3;
                    }
                }
566
#endif // QT_NO_DATESTRING
andersca@apple.com's avatar
andersca@apple.com committed
567
568
569
570
571
            }
            break;

        case QMetaType::QRegExp:
            if (type == RegExp) {
572
/*
darin@apple.com's avatar
darin@apple.com committed
573
                RegExpObject *re = static_cast<RegExpObject*>(object);
andersca@apple.com's avatar
andersca@apple.com committed
574
575
*/
                // Attempt to convert.. a bit risky
576
                UString ustring = value.toString(exec);
barraclough@apple.com's avatar
barraclough@apple.com committed
577
                QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
andersca@apple.com's avatar
andersca@apple.com committed
578
579

                // this is of the form '/xxxxxx/i'
580
581
                int firstSlash = qstring.indexOf(QLatin1Char('/'));
                int lastSlash = qstring.lastIndexOf(QLatin1Char('/'));
andersca@apple.com's avatar
andersca@apple.com committed
582
583
584
585
586
                if (firstSlash >=0 && lastSlash > firstSlash) {
                    QRegExp realRe;

                    realRe.setPattern(qstring.mid(firstSlash + 1, lastSlash - firstSlash - 1));

587
                    if (qstring.mid(lastSlash + 1).contains(QLatin1Char('i')))
andersca@apple.com's avatar
andersca@apple.com committed
588
589
                        realRe.setCaseSensitivity(Qt::CaseInsensitive);

590
                    ret = QVariant::fromValue(realRe);
andersca@apple.com's avatar
andersca@apple.com committed
591
592
593
594
595
                    dist = 0;
                } else {
                    qConvDebug() << "couldn't parse a JS regexp";
                }
            } else if (type == String) {
596
                UString ustring = value.toString(exec);
barraclough@apple.com's avatar
barraclough@apple.com committed
597
                QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
andersca@apple.com's avatar
andersca@apple.com committed
598
599
600

                QRegExp re(qstring);
                if (re.isValid()) {
601
                    ret = QVariant::fromValue(re);
andersca@apple.com's avatar
andersca@apple.com committed
602
603
604
605
606
607
608
                    dist = 10;
                }
            }
            break;

        case QMetaType::QObjectStar:
            if (type == QObj) {
609
                QtInstance* qtinst = QtInstance::getInstance(object);
andersca@apple.com's avatar
andersca@apple.com committed
610
611
612
                if (qtinst) {
                    if (qtinst->getObject()) {
                        qConvDebug() << "found instance, with object:" << (void*) qtinst->getObject();
613
                        ret = QVariant::fromValue(qtinst->getObject());
andersca@apple.com's avatar
andersca@apple.com committed
614
615
616
617
618
619
620
621
622
623
                        qConvDebug() << ret;
                        dist = 0;
                    } else {
                        qConvDebug() << "can't convert deleted qobject";
                    }
                } else {
                    qConvDebug() << "wasn't a qtinstance";
                }
            } else if (type == Null) {
                QObject* nullobj = 0;
624
                ret = QVariant::fromValue(nullobj);
andersca@apple.com's avatar
andersca@apple.com committed
625
626
627
628
629
630
631
632
                dist = 0;
            } else {
                qConvDebug() << "previous type was not an object:" << type;
            }
            break;

        case QMetaType::VoidStar:
            if (type == QObj) {
633
                QtInstance* qtinst = QtInstance::getInstance(object);
andersca@apple.com's avatar
andersca@apple.com committed
634
635
636
                if (qtinst) {
                    if (qtinst->getObject()) {
                        qConvDebug() << "found instance, with object:" << (void*) qtinst->getObject();
637
                        ret = QVariant::fromValue((void *)qtinst->getObject());
andersca@apple.com's avatar
andersca@apple.com committed
638
639
640
641
642
643
644
645
646
                        qConvDebug() << ret;
                        dist = 0;
                    } else {
                        qConvDebug() << "can't convert deleted qobject";
                    }
                } else {
                    qConvDebug() << "wasn't a qtinstance";
                }
            } else if (type == Null) {
647
                ret = QVariant::fromValue((void*)0);
andersca@apple.com's avatar
andersca@apple.com committed
648
649
650
651
                dist = 0;
            } else if (type == Number) {
                // I don't think that converting a double to a pointer is a wise
                // move.  Except maybe 0.
652
                qConvDebug() << "got number for void * - not converting, seems unsafe:" << value.toNumber(exec);
andersca@apple.com's avatar
andersca@apple.com committed
653
654
655
656
657
658
659
660
661
            } else {
                qConvDebug() << "void* - unhandled type" << type;
            }
            break;

        default:
            // Non const type ids
            if (hint == (QMetaType::Type) qMetaTypeId<QObjectList>())
            {
662
663
664
665
666
667
                if (type == RTArray) {
                    RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);

                    QObjectList result;
                    int len = rtarray->getLength();
                    for (int i = 0; i < len; ++i) {
ggaren@apple.com's avatar
ggaren@apple.com committed
668
                        JSValue val = rtarray->getConcreteArray()->valueAt(exec, i);
669
                        int itemdist = -1;
670
                        QVariant item = convertValueToQVariant(exec, val, QMetaType::QObjectStar, &itemdist, visitedObjects, recursionLimit);
671
672
673
674
675
676
677
678
679
680
681
                        if (itemdist >= 0)
                            result.append(item.value<QObject*>());
                        else
                            break;
                    }
                    // If we didn't fail conversion
                    if (result.count() == len) {
                        dist = 5;
                        ret = QVariant::fromValue(result);
                    }
                } else if (type == Array) {
682
                    JSObject* object = value.toObject(exec);
darin@apple.com's avatar
darin@apple.com committed
683
                    JSArray* array = static_cast<JSArray *>(object);
andersca@apple.com's avatar
andersca@apple.com committed
684
                    QObjectList result;
685
                    int len = array->length();
andersca@apple.com's avatar
andersca@apple.com committed
686
                    for (int i = 0; i < len; ++i) {
ggaren@apple.com's avatar
ggaren@apple.com committed
687
                        JSValue val = array->get(exec, i);
andersca@apple.com's avatar
andersca@apple.com committed
688
                        int itemdist = -1;
689
                        QVariant item = convertValueToQVariant(exec, val, QMetaType::QObjectStar, &itemdist, visitedObjects, recursionLimit);
andersca@apple.com's avatar
andersca@apple.com committed
690
691
692
693
694
695
696
697
698
699
700
701
702
703
                        if (itemdist >= 0)
                            result.append(item.value<QObject*>());
                        else
                            break;
                    }
                    // If we didn't fail conversion
                    if (result.count() == len) {
                        dist = 5;
                        ret = QVariant::fromValue(result);
                    }
                } else {
                    // Make a single length array
                    QObjectList result;
                    int itemdist = -1;
704
                    QVariant item = convertValueToQVariant(exec, value, QMetaType::QObjectStar, &itemdist, visitedObjects, recursionLimit);
andersca@apple.com's avatar
andersca@apple.com committed
705
706
707
708
709
710
711
712
                    if (itemdist >= 0) {
                        result.append(item.value<QObject*>());
                        dist = 10;
                        ret = QVariant::fromValue(result);
                    }
                }
                break;
            } else if (hint == (QMetaType::Type) qMetaTypeId<QList<int> >()) {
713
714
715
716
717
718
                if (type == RTArray) {
                    RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);

                    QList<int> result;
                    int len = rtarray->getLength();
                    for (int i = 0; i < len; ++i) {
ggaren@apple.com's avatar
ggaren@apple.com committed
719
                        JSValue val = rtarray->getConcreteArray()->valueAt(exec, i);
720
                        int itemdist = -1;
721
                        QVariant item = convertValueToQVariant(exec, val, QMetaType::Int, &itemdist, visitedObjects, recursionLimit);
722
723
724
725
726
727
728
729
730
731
732
                        if (itemdist >= 0)
                            result.append(item.value<int>());
                        else
                            break;
                    }
                    // If we didn't fail conversion
                    if (result.count() == len) {
                        dist = 5;
                        ret = QVariant::fromValue(result);
                    }
                } else if (type == Array) {
darin@apple.com's avatar
darin@apple.com committed
733
                    JSArray* array = static_cast<JSArray *>(object);
andersca@apple.com's avatar
andersca@apple.com committed
734
735

                    QList<int> result;
736
                    int len = array->length();
andersca@apple.com's avatar
andersca@apple.com committed
737
                    for (int i = 0; i < len; ++i) {
ggaren@apple.com's avatar
ggaren@apple.com committed
738
                        JSValue val = array->get(exec, i);
andersca@apple.com's avatar
andersca@apple.com committed
739
                        int itemdist = -1;
740
                        QVariant item = convertValueToQVariant(exec, val, QMetaType::Int, &itemdist, visitedObjects, recursionLimit);
andersca@apple.com's avatar
andersca@apple.com committed
741
742
743
744
745
746
747
748
749
750
751
752
753
754
                        if (itemdist >= 0)
                            result.append(item.value<int>());
                        else
                            break;
                    }
                    // If we didn't fail conversion
                    if (result.count() == len) {
                        dist = 5;
                        ret = QVariant::fromValue(result);
                    }
                } else {
                    // Make a single length array
                    QList<int> result;
                    int itemdist = -1;
755
                    QVariant item = convertValueToQVariant(exec, value, QMetaType::Int, &itemdist, visitedObjects, recursionLimit);
andersca@apple.com's avatar
andersca@apple.com committed
756
757
758
759
760
761
762
                    if (itemdist >= 0) {
                        result.append(item.value<int>());
                        dist = 10;
                        ret = QVariant::fromValue(result);
                    }
                }
                break;
763
764
            } else if (QtPixmapInstance::canHandle(static_cast<QMetaType::Type>(hint))) {
                ret = QtPixmapInstance::variantFromObject(object, static_cast<QMetaType::Type>(hint));
765
766
767
            } else if (hint == (QMetaType::Type) qMetaTypeId<QWebElement>()) {
                if (object && object->inherits(&JSHTMLElement::s_info))
                    ret = QVariant::fromValue<QWebElement>(QtWebElementRuntime::create((static_cast<JSHTMLElement*>(object))->impl()));
768
769
                else if (object && object->inherits(&JSDocument::s_info))
                    ret = QVariant::fromValue<QWebElement>(QtWebElementRuntime::create((static_cast<JSDocument*>(object))->impl()->documentElement()));
770
771
                else
                    ret = QVariant::fromValue<QWebElement>(QWebElement());
772
773
774
            } else if (hint == (QMetaType::Type) qMetaTypeId<QDRTNode>()) {
                if (object && object->inherits(&JSNode::s_info))
                    ret = QVariant::fromValue<QDRTNode>(QtDRTNodeRuntime::create((static_cast<JSNode*>(object))->impl()));
andersca@apple.com's avatar
andersca@apple.com committed
775
            } else if (hint == (QMetaType::Type) qMetaTypeId<QVariant>()) {
776
                if (value.isUndefinedOrNull()) {
777
778
779
780
                    if (distance)
                        *distance = 1;
                    return QVariant();
                } else {
781
782
783
784
785
786
                    if (type == Object) {
                        // Since we haven't really visited this object yet, we remove it
                        visitedObjects->remove(object);
                    }

                    // And then recurse with the autodetect flag
787
                    ret = convertValueToQVariant(exec, value, QMetaType::Void, distance, visitedObjects, recursionLimit);
788
789
                    dist = 10;
                }
andersca@apple.com's avatar
andersca@apple.com committed
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
                break;
            }

            dist = 10;
            break;
    }

    if (!ret.isValid())
        dist = -1;
    if (distance)
        *distance = dist;

    return ret;
}

ggaren@apple.com's avatar
ggaren@apple.com committed
805
QVariant convertValueToQVariant(ExecState* exec, JSValue value, QMetaType::Type hint, int *distance)
806
{
807
    const int recursionLimit = 200;
808
    HashSet<JSObject*> visitedObjects;
809
    return convertValueToQVariant(exec, value, hint, distance, &visitedObjects, recursionLimit);
810
811
}

ggaren@apple.com's avatar
ggaren@apple.com committed
812
JSValue convertQVariantToValue(ExecState* exec, PassRefPtr<RootObject> root, const QVariant& variant)
andersca@apple.com's avatar
andersca@apple.com committed
813
814
815
816
{
    // Variants with QObject * can be isNull but not a null pointer
    // An empty QString variant is also null
    QMetaType::Type type = (QMetaType::Type) variant.userType();
817
818

    qConvDebug() << "convertQVariantToValue: metatype:" << type << ", isnull: " << variant.isNull();
andersca@apple.com's avatar
andersca@apple.com committed
819
820
821
822
823
824
825
826
    if (variant.isNull() &&
        type != QMetaType::QObjectStar &&
        type != QMetaType::VoidStar &&
        type != QMetaType::QWidgetStar &&
        type != QMetaType::QString) {
        return jsNull();
    }

ap@webkit.org's avatar
ap@webkit.org committed
827
    JSLock lock(SilenceAssertionsOnly);
ap@webkit.org's avatar
ap@webkit.org committed
828

andersca@apple.com's avatar
andersca@apple.com committed
829
830
831
832
833
834
835
836
837
838
839
840
841
    if (type == QMetaType::Bool)
        return jsBoolean(variant.toBool());

    if (type == QMetaType::Int ||
        type == QMetaType::UInt ||
        type == QMetaType::Long ||
        type == QMetaType::ULong ||
        type == QMetaType::LongLong ||
        type == QMetaType::ULongLong ||
        type == QMetaType::Short ||
        type == QMetaType::UShort ||
        type == QMetaType::Float ||
        type == QMetaType::Double)
842
        return jsNumber(variant.toDouble());
andersca@apple.com's avatar
andersca@apple.com committed
843
844
845
846
847

    if (type == QMetaType::QRegExp) {
        QRegExp re = variant.value<QRegExp>();

        if (re.isValid()) {
848
            UString pattern((UChar*)re.pattern().utf16(), re.pattern().length());
barraclough@apple.com's avatar
barraclough@apple.com committed
849
            RegExpFlags flags = (re.caseSensitivity() == Qt::CaseInsensitive) ? FlagIgnoreCase : NoFlags;
850

barraclough@apple.com's avatar
barraclough@apple.com committed
851
            RefPtr<JSC::RegExp> regExp = JSC::RegExp::create(&exec->globalData(), pattern, flags);
852
            if (regExp->isValid())
oliver@apple.com's avatar
oliver@apple.com committed
853
                return new (exec) RegExpObject(exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->regExpStructure(), regExp.release());
barraclough@apple.com's avatar
barraclough@apple.com committed
854
            return jsNull();
andersca@apple.com's avatar
andersca@apple.com committed
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
        }
    }

    if (type == QMetaType::QDateTime ||
        type == QMetaType::QDate ||
        type == QMetaType::QTime) {

        QDate date = QDate::currentDate();
        QTime time(0,0,0); // midnight

        if (type == QMetaType::QDate)
            date = variant.value<QDate>();
        else if (type == QMetaType::QTime)
            time = variant.value<QTime>();
        else {
            QDateTime dt = variant.value<QDateTime>().toLocalTime();
            date = dt.date();
            time = dt.time();
        }

        // Dates specified this way are in local time (we convert DateTimes above)
876
        GregorianDateTime dt;
877
878
879
880
881
882
883
        dt.year = date.year() - 1900;
        dt.month = date.month() - 1;
        dt.monthDay = date.day();
        dt.hour = time.hour();
        dt.minute = time.minute();
        dt.second = time.second();
        dt.isDST = -1;
884
        double ms = gregorianDateTimeToMS(exec, dt, time.msec(), /*inputIsUTC*/ false);
885

886
        return new (exec) DateInstance(exec, trunc(ms));
andersca@apple.com's avatar
andersca@apple.com committed
887
888
889
    }

    if (type == QMetaType::QByteArray) {
hausmann@webkit.org's avatar
hausmann@webkit.org committed
890
891
        QByteArray qtByteArray = variant.value<QByteArray>();
        WTF::RefPtr<WTF::ByteArray> wtfByteArray = WTF::ByteArray::create(qtByteArray.length());
892
        memcpy(wtfByteArray->data(), qtByteArray.constData(), qtByteArray.length());
893
        return new (exec) JSC::JSByteArray(exec, JSC::JSByteArray::createStructure(jsNull()), wtfByteArray.get());
andersca@apple.com's avatar
andersca@apple.com committed
894
895
896
897
    }

    if (type == QMetaType::QObjectStar || type == QMetaType::QWidgetStar) {
        QObject* obj = variant.value<QObject*>();
898
899
        if (!obj)
            return jsNull();
hausmann@webkit.org's avatar
hausmann@webkit.org committed
900
        return QtInstance::getQtInstance(obj, root, QScriptEngine::QtOwnership)->createRuntimeObject(exec);
andersca@apple.com's avatar
andersca@apple.com committed
901
902
    }

903
    if (QtPixmapInstance::canHandle(static_cast<QMetaType::Type>(variant.type())))
904
        return QtPixmapInstance::createPixmapRuntimeObject(exec, root, variant);
905

906
907
908
909
910
911
912
913
914
915
916
    if (type == qMetaTypeId<QWebElement>()) {
        if (!root->globalObject()->inherits(&JSDOMWindow::s_info))
            return jsUndefined();

        Document* document = (static_cast<JSDOMWindow*>(root->globalObject()))->impl()->document();
        if (!document)
            return jsUndefined();

        return toJS(exec, toJSDOMGlobalObject(document, exec), QtWebElementRuntime::get(variant.value<QWebElement>()));
    }

917
918
919
920
921
922
923
924
925
926
927
    if (type == qMetaTypeId<QDRTNode>()) {
        if (!root->globalObject()->inherits(&JSDOMWindow::s_info))
            return jsUndefined();

        Document* document = (static_cast<JSDOMWindow*>(root->globalObject()))->impl()->document();
        if (!document)
            return jsUndefined();

        return toJS(exec, toJSDOMGlobalObject(document, exec), QtDRTNodeRuntime::get(variant.value<QDRTNode>()));
    }

andersca@apple.com's avatar
andersca@apple.com committed
928
929
    if (type == QMetaType::QVariantMap) {
        // create a new object, and stuff properties into it
930
        JSObject* ret = constructEmptyObject(exec);
andersca@apple.com's avatar
andersca@apple.com committed
931
932
933
934
        QVariantMap map = variant.value<QVariantMap>();
        QVariantMap::const_iterator i = map.constBegin();
        while (i != map.constEnd()) {
            QString s = i.key();
935
            JSValue val = convertQVariantToValue(exec, root.get(), i.value());
936
937
            if (val) {
                PutPropertySlot slot;
938
                ret->put(exec, Identifier(exec, reinterpret_cast_ptr<const UChar *>(s.constData()), s.length()), val, slot);
939
940
                // ### error case?
            }
andersca@apple.com's avatar
andersca@apple.com committed
941
942
943
944
945
946
947
948
949
            ++i;
        }

        return ret;
    }

    // List types
    if (type == QMetaType::QVariantList) {
        QVariantList vl = variant.toList();
950
        qConvDebug() << "got a " << vl.count() << " length list:" << vl;
ap@webkit.org's avatar
ap@webkit.org committed
951
        return new (exec) RuntimeArray(exec, new QtArray<QVariant>(vl, QMetaType::Void, root));
andersca@apple.com's avatar
andersca@apple.com committed
952
953
    } else if (type == QMetaType::QStringList) {
        QStringList sl = variant.value<QStringList>();
ap@webkit.org's avatar
ap@webkit.org committed
954
        return new (exec) RuntimeArray(exec, new QtArray<QString>(sl, QMetaType::QString, root));
andersca@apple.com's avatar
andersca@apple.com committed
955
956
    } else if (type == (QMetaType::Type) qMetaTypeId<QObjectList>()) {
        QObjectList ol= variant.value<QObjectList>();
ap@webkit.org's avatar
ap@webkit.org committed
957
        return new (exec) RuntimeArray(exec, new QtArray<QObject*>(ol, QMetaType::QObjectStar, root));
andersca@apple.com's avatar
andersca@apple.com committed
958
959
    } else if (type == (QMetaType::Type)qMetaTypeId<QList<int> >()) {
        QList<int> il= variant.value<QList<int> >();
ap@webkit.org's avatar
ap@webkit.org committed
960
        return new (exec) RuntimeArray(exec, new QtArray<int>(il, QMetaType::Int, root));
andersca@apple.com's avatar
andersca@apple.com committed
961
962
963
964
965
966
967
968
969
970
971
    }

    if (type == (QMetaType::Type)qMetaTypeId<QVariant>()) {
        QVariant real = variant.value<QVariant>();
        qConvDebug() << "real variant is:" << real;
        return convertQVariantToValue(exec, root, real);
    }

    qConvDebug() << "fallback path for" << variant << variant.userType();

    QString string = variant.toString();
darin@apple.com's avatar
darin@apple.com committed
972
    UString ustring((UChar*)string.utf16(), string.length());
ap@webkit.org's avatar
ap@webkit.org committed
973
    return jsString(exec, ustring);
andersca@apple.com's avatar
andersca@apple.com committed
974
975
976
977
978
979
980
981
}

// ===============

// Qt-like macros
#define QW_D(Class) Class##Data* d = d_func()
#define QW_DS(Class,Instance) Class##Data* d = Instance->d_func()

982
const ClassInfo QtRuntimeMethod::s_info = { "QtRuntimeMethod", &InternalFunction::s_info, 0, 0 };
983
984

QtRuntimeMethod::QtRuntimeMethod(QtRuntimeMethodData* dd, ExecState* exec, const Identifier& ident, PassRefPtr<QtInstance> inst)
oliver@apple.com's avatar
oliver@apple.com committed
985
    : InternalFunction(&exec->globalData(), exec->lexicalGlobalObject(), deprecatedGetDOMStructure<QtRuntimeMethod>(exec), ident)
andersca@apple.com's avatar
andersca@apple.com committed
986
987
988
989
990
991
992
993
    , d_ptr(dd)
{
    QW_D(QtRuntimeMethod);
    d->m_instance = inst;
}

QtRuntimeMethod::~QtRuntimeMethod()
{
hausmann@webkit.org's avatar
hausmann@webkit.org committed
994
995
    QW_D(QtRuntimeMethod);
    d->m_instance->removeCachedMethod(this);
andersca@apple.com's avatar
andersca@apple.com committed
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
    delete d_ptr;
}

// ===============

QtRuntimeMethodData::~QtRuntimeMethodData()
{
}

QtRuntimeMetaMethodData::~QtRuntimeMetaMethodData()
{

}

QtRuntimeConnectionMethodData::~QtRuntimeConnectionMethodData()
{

}

// ===============

// Type conversion metadata (from QtScript originally)
class QtMethodMatchType
{
public:
    enum Kind {
        Invalid,
        Variant,
        MetaType,
        Unresolved,
        MetaEnum
    };


    QtMethodMatchType()
        : m_kind(Invalid) { }

    Kind kind() const
    { return m_kind; }

    QMetaType::Type typeId() const;

    bool isValid() const
    { return (m_kind != Invalid); }

    bool isVariant() const
    { return (m_kind == Variant); }

    bool isMetaType() const
    { return (m_kind == MetaType); }

    bool isUnresolved() const
    { return (m_kind == Unresolved); }

    bool isMetaEnum() const
    { return (m_kind == MetaEnum); }

    QByteArray name() const;

    int enumeratorIndex() const
    { Q_ASSERT(isMetaEnum()); return m_typeId; }

    static QtMethodMatchType variant()
    { return QtMethodMatchType(Variant); }

    static QtMethodMatchType metaType(int typeId, const QByteArray &name)
    { return QtMethodMatchType(MetaType, typeId, name); }

    static QtMethodMatchType metaEnum(int enumIndex, const QByteArray &name)
    { return QtMethodMatchType(MetaEnum, enumIndex, name); }

    static QtMethodMatchType unresolved(const QByteArray &name)
    { return QtMethodMatchType(Unresolved, /*typeId=*/0, name); }

private:
    QtMethodMatchType(Kind kind, int typeId = 0, const QByteArray &name = QByteArray())
        : m_kind(kind), m_typeId(typeId), m_name(name) { }

    Kind m_kind;
    int m_typeId;
    QByteArray m_name;
};

QMetaType::Type QtMethodMatchType::typeId() const
{
    if (isVariant())
        return (QMetaType::Type) QMetaType::type("QVariant");
    return (QMetaType::Type) (isMetaEnum() ? QMetaType::Int : m_typeId);
}

QByteArray QtMethodMatchType::name() const
{
    if (!m_name.