~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/bridge/qt/qt_runtime.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
 
3
 *
 
4
 *  This library is free software; you can redistribute it and/or
 
5
 *  modify it under the terms of the GNU Lesser General Public
 
6
 *  License as published by the Free Software Foundation; either
 
7
 *  version 2 of the License, or (at your option) any later version.
 
8
 *
 
9
 *  This library is distributed in the hope that it will be useful,
 
10
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
 *  Lesser General Public License for more details.
 
13
 *
 
14
 *  You should have received a copy of the GNU Lesser General Public
 
15
 *  License along with this library; if not, write to the Free Software
 
16
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 
17
 *
 
18
 */
 
19
 
 
20
#include "config.h"
 
21
#include "qt_runtime.h"
 
22
 
 
23
#include "APICast.h"
 
24
#include "BooleanObject.h"
 
25
#include "DateInstance.h"
 
26
#include "DatePrototype.h"
 
27
#include "FunctionPrototype.h"
 
28
#include "Interpreter.h"
 
29
#include "JSArray.h"
 
30
#include "JSContextRefPrivate.h"
 
31
#include "JSDOMBinding.h"
 
32
#include "JSDOMWindow.h"
 
33
#include "JSDocument.h"
 
34
#include "JSGlobalObject.h"
 
35
#include "JSHTMLElement.h"
 
36
#include "JSLock.h"
 
37
#include "JSObject.h"
 
38
#include "JSRetainPtr.h"
 
39
#include "JSUint8ClampedArray.h"
 
40
#include "ObjectPrototype.h"
 
41
#include "PropertyNameArray.h"
 
42
#include "qdatetime.h"
 
43
#include "qdebug.h"
 
44
#include "qmetaobject.h"
 
45
#include "qmetatype.h"
 
46
#include "qobject.h"
 
47
#include "qstringlist.h"
 
48
#include "qt_instance.h"
 
49
#include "qt_pixmapruntime.h"
 
50
#include "qvarlengtharray.h"
 
51
#include <JSFunction.h>
 
52
 
 
53
#include <wtf/DateMath.h>
 
54
 
 
55
#include <limits.h>
 
56
#include <runtime/Error.h>
 
57
#include <runtime_array.h>
 
58
#include <runtime_object.h>
 
59
 
 
60
// QtScript has these
 
61
Q_DECLARE_METATYPE(QObjectList);
 
62
Q_DECLARE_METATYPE(QList<int>);
 
63
Q_DECLARE_METATYPE(QVariant);
 
64
 
 
65
using namespace WebCore;
 
66
 
 
67
namespace JSC {
 
68
namespace Bindings {
 
69
 
 
70
// Debugging
 
71
//#define QTWK_RUNTIME_CONVERSION_DEBUG
 
72
//#define QTWK_RUNTIME_MATCH_DEBUG
 
73
 
 
74
class QWKNoDebug
 
75
{
 
76
public:
 
77
    inline QWKNoDebug(){}
 
78
    inline ~QWKNoDebug(){}
 
79
 
 
80
    template<typename T>
 
81
    inline QWKNoDebug &operator<<(const T &) { return *this; }
 
82
};
 
83
 
 
84
#ifdef QTWK_RUNTIME_CONVERSION_DEBUG
 
85
#define qConvDebug() qDebug()
 
86
#else
 
87
#define qConvDebug() QWKNoDebug()
 
88
#endif
 
89
 
 
90
#ifdef QTWK_RUNTIME_MATCH_DEBUG
 
91
#define qMatchDebug() qDebug()
 
92
#else
 
93
#define qMatchDebug() QWKNoDebug()
 
94
#endif
 
95
 
 
96
typedef enum {
 
97
    Variant = 0,
 
98
    Number,
 
99
    Boolean,
 
100
    RTString,
 
101
    Date,
 
102
    Array,
 
103
    QObj,
 
104
    Object,
 
105
    Null,
 
106
    RTUint8ClampedArray
 
107
} JSRealType;
 
108
 
 
109
#if defined(QTWK_RUNTIME_CONVERSION_DEBUG) || defined(QTWK_RUNTIME_MATCH_DEBUG)
 
110
QDebug operator<<(QDebug dbg, const JSRealType &c)
 
111
{
 
112
     const char *map[] = { "Variant", "Number", "Boolean", "RTString", "Date",
 
113
         "Array", "RTObject", "Object", "Null"};
 
114
 
 
115
     dbg.nospace() << "JSType(" << ((int)c) << ", " <<  map[c] << ")";
 
116
 
 
117
     return dbg.space();
 
118
}
 
119
#endif
 
120
 
 
121
void setException(JSContextRef context, JSValueRef* exception, const QString& text)
 
122
{
 
123
    if (!exception)
 
124
        return;
 
125
 
 
126
    JSStringRef errorStr = JSStringCreateWithUTF8CString(text.toUtf8());
 
127
    JSValueRef errorVal[] = { JSValueMakeString(context, errorStr) };
 
128
    *exception = JSObjectMakeError(context, 1, errorVal, 0);
 
129
    JSStringRelease(errorStr);
 
130
}
 
131
 
 
132
struct RuntimeConversion {
 
133
    ConvertToJSValueFunction toJSValueFunc;
 
134
    ConvertToVariantFunction toVariantFunc;
 
135
};
 
136
 
 
137
typedef QHash<int, RuntimeConversion> RuntimeConversionTable;
 
138
Q_GLOBAL_STATIC(RuntimeConversionTable, customRuntimeConversions)
 
139
 
 
140
void registerCustomType(int qtMetaTypeId, ConvertToVariantFunction toVariantFunc, ConvertToJSValueFunction toJSValueFunc)
 
141
{
 
142
    RuntimeConversion conversion;
 
143
    conversion.toJSValueFunc = toJSValueFunc;
 
144
    conversion.toVariantFunc = toVariantFunc;
 
145
    customRuntimeConversions()->insert(qtMetaTypeId, conversion);
 
146
}
 
147
 
 
148
static bool isJSUint8ClampedArray(JSObjectRef object)
 
149
{
 
150
    return toJS(object)->inherits(&JSUint8ClampedArray::s_info);
 
151
}
 
152
 
 
153
static bool isJSArray(JSObjectRef object)
 
154
{
 
155
    return toJS(object)->inherits(&JSArray::s_info);
 
156
}
 
157
 
 
158
static bool isJSDate(JSObjectRef object)
 
159
{
 
160
    return toJS(object)->inherits(&DateInstance::s_info);
 
161
}
 
162
 
 
163
static bool isQtObject(JSObjectRef object)
 
164
{
 
165
    return toJS(object)->inherits(&RuntimeObject::s_info);
 
166
}
 
167
 
 
168
static JSRealType valueRealType(JSContextRef context, JSValueRef value, JSValueRef* exception)
 
169
{
 
170
    if (JSValueIsNumber(context, value))
 
171
        return Number;
 
172
    if (JSValueIsString(context, value))
 
173
        return RTString;
 
174
    if (JSValueIsBoolean(context, value))
 
175
        return Boolean;
 
176
    if (JSValueIsNull(context, value))
 
177
        return Null;
 
178
    if (!JSValueIsObject(context, value))
 
179
        return RTString; // I don't know.
 
180
 
 
181
    JSObjectRef object = JSValueToObject(context, value, exception);
 
182
 
 
183
    if (isJSUint8ClampedArray(object))
 
184
        return RTUint8ClampedArray;
 
185
    if (isJSArray(object))
 
186
            return Array;
 
187
    if (isJSDate(object))
 
188
            return Date;
 
189
    if (isQtObject(object))
 
190
            return QObj;
 
191
 
 
192
    return Object;
 
193
}
 
194
 
 
195
static QString toString(JSStringRef stringRef)
 
196
{
 
197
    return QString(reinterpret_cast<const QChar*>(JSStringGetCharactersPtr(stringRef)), JSStringGetLength(stringRef));
 
198
}
 
199
 
 
200
static JSValueRef unwrapBoxedPrimitive(JSContextRef context, JSValueRef value, JSObjectRef obj)
 
201
{
 
202
    JSObject* object = toJS(obj);
 
203
    ExecState* exec = toJS(context);
 
204
    if (object->inherits(&NumberObject::s_info))
 
205
        return toRef(exec, jsNumber(object->toNumber(exec)));
 
206
    if (object->inherits(&StringObject::s_info))
 
207
        return toRef(exec, object->toString(exec));
 
208
    if (object->inherits(&BooleanObject::s_info))
 
209
        return toRef(exec, object->toPrimitive(exec));
 
210
    return value;
 
211
}
 
212
 
 
213
QVariant convertValueToQVariant(JSContextRef, JSValueRef, QMetaType::Type, int*, HashSet<JSObjectRef>*, int, JSValueRef *exception);
 
214
 
 
215
static QVariantMap convertValueToQVariantMap(JSContextRef context, JSObjectRef object, HashSet<JSObjectRef>* visitedObjects, int recursionLimit, JSValueRef* exception)
 
216
{
 
217
    QVariantMap result;
 
218
    JSPropertyNameArrayRef properties = JSObjectCopyPropertyNames(context, object);
 
219
    size_t propertyCount = JSPropertyNameArrayGetCount(properties);
 
220
 
 
221
    for (size_t i = 0; i < propertyCount; ++i) {
 
222
        JSStringRef name = JSPropertyNameArrayGetNameAtIndex(properties, i);
 
223
 
 
224
        int propertyConversionDistance = 0;
 
225
        JSValueRef property = JSObjectGetProperty(context, object, name, exception);
 
226
        QVariant v = convertValueToQVariant(context, property, QMetaType::Void, &propertyConversionDistance, visitedObjects, recursionLimit, exception);
 
227
        if (exception && *exception)
 
228
            *exception = 0;
 
229
        else if (propertyConversionDistance >= 0) {
 
230
            result.insert(toString(name), v);
 
231
        }
 
232
    }
 
233
    JSPropertyNameArrayRelease(properties);
 
234
    return result;
 
235
}
 
236
 
 
237
template <typename ItemType>
 
238
QList<ItemType> convertToList(JSContextRef context, JSRealType type, JSObjectRef object,
 
239
                              JSValueRef value, int* distance, JSValueRef* exception,
 
240
                              const QMetaType::Type typeId = static_cast<QMetaType::Type>(qMetaTypeId<ItemType>()))
 
241
{
 
242
    QList<ItemType> list;
 
243
    if (type == Array) {
 
244
        static JSStringRef lengthStr = JSStringCreateWithUTF8CString("length");
 
245
        JSValueRef lengthVal = JSObjectGetProperty(context, object, lengthStr, exception);
 
246
        size_t length = JSValueToNumber(context, lengthVal, exception);
 
247
        list.reserve(length);
 
248
        for (size_t i = 0; i < length; ++i) {
 
249
            JSValueRef value = JSObjectGetPropertyAtIndex(context, object, i, exception);
 
250
            int itemDistance = -1;
 
251
            QVariant variant = convertValueToQVariant(context, value, typeId, &itemDistance, exception);
 
252
            if (itemDistance >= 0)
 
253
                list << variant.value<ItemType>();
 
254
            else
 
255
                break;
 
256
        }
 
257
        if (list.count() != length)
 
258
            list.clear();
 
259
        else if (distance)
 
260
            *distance = 5;
 
261
    } else {
 
262
        int itemDistance = -1;
 
263
        QVariant variant = convertValueToQVariant(context, value, typeId, &itemDistance, exception);
 
264
        if (itemDistance >= 0) {
 
265
            list << variant.value<ItemType>();
 
266
            if (distance)
 
267
                *distance = 10;
 
268
        }
 
269
    }
 
270
    return list;
 
271
}
 
272
 
 
273
static QString toQString(JSContextRef context, JSValueRef value)
 
274
{
 
275
    JSRetainPtr<JSStringRef> string(Adopt, JSValueToStringCopy(context, value, 0));
 
276
    if (!string)
 
277
        return QString();
 
278
    return QString(reinterpret_cast<const QChar*>(JSStringGetCharactersPtr(string.get())), JSStringGetLength(string.get()));
 
279
}
 
280
 
 
281
static void getGregorianDateTimeUTC(JSContextRef context, JSRealType type, JSValueRef value, JSObjectRef object, JSValueRef* exception, GregorianDateTime* gdt)
 
282
{
 
283
    ExecState* exec = toJS(context);
 
284
    if (type == Date) {
 
285
        JSObject* jsObject = toJS(object);
 
286
        DateInstance* date = asDateInstance(jsObject);
 
287
        gdt->copyFrom(*date->gregorianDateTimeUTC(exec));
 
288
    } else {
 
289
        double ms = JSValueToNumber(context, value, exception);
 
290
        GregorianDateTime convertedGdt;
 
291
        msToGregorianDateTime(exec, ms, /*utc*/ true, convertedGdt);
 
292
        gdt->copyFrom(convertedGdt);
 
293
    }
 
294
}
 
295
 
 
296
static QDateTime toQDateTimeUTC(JSContextRef context, JSRealType type, JSValueRef value, JSObjectRef object, JSValueRef* exception)
 
297
{
 
298
    GregorianDateTime gdt;
 
299
    getGregorianDateTimeUTC(context, type, value, object, exception, &gdt);
 
300
    QDate date(gdt.year(), gdt.month() + 1, gdt.monthDay());
 
301
    QTime time(gdt.hour(), gdt.minute(), gdt.second());
 
302
    return QDateTime(date, time, Qt::UTC);
 
303
}
 
304
 
 
305
QVariant convertValueToQVariant(JSContextRef context, JSValueRef value, QMetaType::Type hint, int *distance, HashSet<JSObjectRef>* visitedObjects, int recursionLimit, JSValueRef* exception)
 
306
{
 
307
    --recursionLimit;
 
308
 
 
309
    if (!value || !recursionLimit)
 
310
        return QVariant();
 
311
 
 
312
    JSObjectRef object = 0;
 
313
    if (JSValueIsObject(context, value)) {
 
314
        object = JSValueToObject(context, value, 0);
 
315
        if (visitedObjects->contains(object))
 
316
            return QVariant();
 
317
 
 
318
        visitedObjects->add(object);
 
319
 
 
320
        value = unwrapBoxedPrimitive(context, value, object);
 
321
    }
 
322
 
 
323
    // check magic pointer values before dereferencing value
 
324
    if (JSValueIsNumber(context, value)
 
325
        && isnan(JSValueToNumber(context, value, exception))) {
 
326
        if (distance)
 
327
            *distance = -1;
 
328
        return QVariant();
 
329
    }
 
330
 
 
331
    if (JSValueIsUndefined(context, value) && hint != QMetaType::QString && hint != (QMetaType::Type) qMetaTypeId<QVariant>()) {
 
332
        if (distance)
 
333
            *distance = -1;
 
334
        return QVariant();
 
335
    }
 
336
 
 
337
    JSRealType type = valueRealType(context, value, exception);
 
338
    if (hint == QMetaType::Void) {
 
339
        switch(type) {
 
340
            case Number:
 
341
                hint = QMetaType::Double;
 
342
                break;
 
343
            case Boolean:
 
344
                hint = QMetaType::Bool;
 
345
                break;
 
346
            case RTString:
 
347
            default:
 
348
                hint = QMetaType::QString;
 
349
                break;
 
350
            case Date:
 
351
                hint = QMetaType::QDateTime;
 
352
                break;
 
353
            case Object:
 
354
                hint = QMetaType::QVariantMap;
 
355
                break;
 
356
            case QObj:
 
357
                hint = QMetaType::QObjectStar;
 
358
                break;
 
359
            case RTUint8ClampedArray:
 
360
                hint = QMetaType::QByteArray;
 
361
                break;
 
362
            case Array:
 
363
                hint = QMetaType::QVariantList;
 
364
                break;
 
365
        }
 
366
    }
 
367
 
 
368
    qConvDebug() << "convertValueToQVariant: jstype is " << type << ", hint is" << hint;
 
369
 
 
370
    if (JSValueIsNull(context, value)
 
371
        && hint != QMetaType::QObjectStar
 
372
        && hint != QMetaType::VoidStar
 
373
        && hint != QMetaType::QString
 
374
        && hint != (QMetaType::Type) qMetaTypeId<QVariant>()) {
 
375
        if (distance)
 
376
            *distance = -1;
 
377
        return QVariant();
 
378
    }
 
379
 
 
380
    QVariant ret;
 
381
    int dist = -1;
 
382
    switch (hint) {
 
383
        case QMetaType::Bool:
 
384
            ret = QVariant(JSValueToBoolean(context, value));
 
385
            if (type == Boolean)
 
386
                dist = 0;
 
387
            else
 
388
                dist = 10;
 
389
            break;
 
390
 
 
391
        case QMetaType::Int:
 
392
        case QMetaType::UInt:
 
393
        case QMetaType::Long:
 
394
        case QMetaType::ULong:
 
395
        case QMetaType::LongLong:
 
396
        case QMetaType::ULongLong:
 
397
        case QMetaType::Short:
 
398
        case QMetaType::UShort:
 
399
        case QMetaType::Float:
 
400
        case QMetaType::Double:
 
401
            ret = QVariant(JSValueToNumber(context, value, 0));
 
402
            ret.convert((QVariant::Type)hint);
 
403
            if (type == Number) {
 
404
                switch (hint) {
 
405
                case QMetaType::Double:
 
406
                    dist = 0;
 
407
                    break;
 
408
                case QMetaType::Float:
 
409
                    dist = 1;
 
410
                    break;
 
411
                case QMetaType::LongLong:
 
412
                case QMetaType::ULongLong:
 
413
                    dist = 2;
 
414
                    break;
 
415
                case QMetaType::Long:
 
416
                case QMetaType::ULong:
 
417
                    dist = 3;
 
418
                    break;
 
419
                case QMetaType::Int:
 
420
                case QMetaType::UInt:
 
421
                    dist = 4;
 
422
                    break;
 
423
                case QMetaType::Short:
 
424
                case QMetaType::UShort:
 
425
                    dist = 5;
 
426
                    break;
 
427
                    break;
 
428
                default:
 
429
                    dist = 10;
 
430
                    break;
 
431
                }
 
432
            } else {
 
433
                dist = 10;
 
434
            }
 
435
            break;
 
436
 
 
437
        case QMetaType::QChar:
 
438
            if (type == Number || type == Boolean) {
 
439
                ret = QVariant(QChar((ushort)JSValueToNumber(context, value, 0)));
 
440
                if (type == Boolean)
 
441
                    dist = 3;
 
442
                else
 
443
                    dist = 6;
 
444
            } else {
 
445
                JSRetainPtr<JSStringRef> str(Adopt, JSValueToStringCopy(context, value, exception));
 
446
                QChar ch;
 
447
                if (str && JSStringGetLength(str.get()) > 0)
 
448
                    ch = *reinterpret_cast<const QChar*>(JSStringGetCharactersPtr(str.get()));
 
449
                ret = QVariant(ch);
 
450
                if (type == RTString)
 
451
                    dist = 3;
 
452
                else
 
453
                    dist = 10;
 
454
            }
 
455
            break;
 
456
 
 
457
        case QMetaType::QString: {
 
458
            if (JSValueIsNull(context, value) || JSValueIsUndefined(context, value)) {
 
459
                if (distance)
 
460
                    *distance = 1;
 
461
                return QString();
 
462
            }
 
463
            JSRetainPtr<JSStringRef> str(Adopt, JSValueToStringCopy(context, value, exception));
 
464
            if (str) {
 
465
                QString string(reinterpret_cast<const QChar*>(JSStringGetCharactersPtr(str.get())), JSStringGetLength(str.get()));
 
466
                ret = QVariant(string);
 
467
                if (type == RTString)
 
468
                    dist = 0;
 
469
                else
 
470
                    dist = 10;
 
471
            }
 
472
            break;
 
473
        }
 
474
 
 
475
        case QMetaType::QVariantMap:
 
476
            if (type == Object || type == Array) {
 
477
                ret = QVariant(convertValueToQVariantMap(context, object, visitedObjects, recursionLimit, exception));
 
478
                // Those types can still have perfect matches, e.g. 'bool' if value is a Boolean Object.
 
479
                dist = 1;
 
480
            }
 
481
            break;
 
482
 
 
483
        case QMetaType::QVariantList:
 
484
            ret = QVariant(convertToList<QVariant>(context, type, object, value, &dist, exception, QMetaType::Void));
 
485
            break;
 
486
 
 
487
        case QMetaType::QStringList: {
 
488
            ret = QVariant(convertToList<QString>(context, type, object, value, &dist, exception));
 
489
            break;
 
490
        }
 
491
 
 
492
        case QMetaType::QByteArray: {
 
493
            if (type == RTUint8ClampedArray) {
 
494
                WTF::Uint8ClampedArray* arr = toUint8ClampedArray(toJS(toJS(context), value));
 
495
                ret = QVariant(QByteArray(reinterpret_cast<const char*>(arr->data()), arr->length()));
 
496
                dist = 0;
 
497
            } else {
 
498
                ret = QVariant(toQString(context, value).toLatin1());
 
499
                if (type == RTString)
 
500
                    dist = 5;
 
501
                else
 
502
                    dist = 10;
 
503
            }
 
504
            break;
 
505
        }
 
506
 
 
507
        case QMetaType::QDateTime:
 
508
        case QMetaType::QDate:
 
509
        case QMetaType::QTime:
 
510
            if (type == Date || type == Number) {
 
511
                QDateTime dt = toQDateTimeUTC(context, type, value, object, exception);
 
512
                const bool isNumber = (type == Number);
 
513
                if (hint == QMetaType::QDateTime) {
 
514
                    ret = dt;
 
515
                    dist = isNumber ? 6 : 0;
 
516
                } else if (hint == QMetaType::QDate) {
 
517
                    ret = dt.date();
 
518
                    dist = isNumber ? 8 : 1;
 
519
                } else {
 
520
                    ret = dt.time();
 
521
                    dist = isNumber ? 10 : 2;
 
522
                }
 
523
            } else if (type == RTString) {
 
524
                QString qstring = toQString(context, value);
 
525
                if (hint == QMetaType::QDateTime) {
 
526
                    QDateTime dt = QDateTime::fromString(qstring, Qt::ISODate);
 
527
                    if (!dt.isValid())
 
528
                        dt = QDateTime::fromString(qstring, Qt::TextDate);
 
529
                    if (!dt.isValid())
 
530
                        dt = QDateTime::fromString(qstring, Qt::SystemLocaleDate);
 
531
                    if (!dt.isValid())
 
532
                        dt = QDateTime::fromString(qstring, Qt::LocaleDate);
 
533
                    if (dt.isValid()) {
 
534
                        ret = dt;
 
535
                        dist = 2;
 
536
                    }
 
537
                } else if (hint == QMetaType::QDate) {
 
538
                    QDate dt = QDate::fromString(qstring, Qt::ISODate);
 
539
                    if (!dt.isValid())
 
540
                        dt = QDate::fromString(qstring, Qt::TextDate);
 
541
                    if (!dt.isValid())
 
542
                        dt = QDate::fromString(qstring, Qt::SystemLocaleDate);
 
543
                    if (!dt.isValid())
 
544
                        dt = QDate::fromString(qstring, Qt::LocaleDate);
 
545
                    if (dt.isValid()) {
 
546
                        ret = dt;
 
547
                        dist = 3;
 
548
                    }
 
549
                } else {
 
550
                    QTime dt = QTime::fromString(qstring, Qt::ISODate);
 
551
                    if (!dt.isValid())
 
552
                        dt = QTime::fromString(qstring, Qt::TextDate);
 
553
                    if (!dt.isValid())
 
554
                        dt = QTime::fromString(qstring, Qt::SystemLocaleDate);
 
555
                    if (!dt.isValid())
 
556
                        dt = QTime::fromString(qstring, Qt::LocaleDate);
 
557
                    if (dt.isValid()) {
 
558
                        ret = dt;
 
559
                        dist = 3;
 
560
                    }
 
561
                }
 
562
            }
 
563
            break;
 
564
 
 
565
        case QMetaType::QObjectStar:
 
566
            if (type == QObj) {
 
567
                QtInstance* qtinst = QtInstance::getInstance(toJS(object));
 
568
                if (qtinst) {
 
569
                    if (qtinst->getObject()) {
 
570
                        qConvDebug() << "found instance, with object:" << (void*) qtinst->getObject();
 
571
                        ret = QVariant::fromValue(qtinst->getObject());
 
572
                        qConvDebug() << ret;
 
573
                        dist = 0;
 
574
                    } else {
 
575
                        qConvDebug() << "can't convert deleted qobject";
 
576
                    }
 
577
                } else {
 
578
                    qConvDebug() << "wasn't a qtinstance";
 
579
                }
 
580
            } else if (type == Null) {
 
581
                QObject* nullobj = 0;
 
582
                ret = QVariant::fromValue(nullobj);
 
583
                dist = 0;
 
584
            } else {
 
585
                qConvDebug() << "previous type was not an object:" << type;
 
586
            }
 
587
            break;
 
588
 
 
589
        case QMetaType::VoidStar:
 
590
            if (type == QObj) {
 
591
                QtInstance* qtinst = QtInstance::getInstance(toJS(object));
 
592
                if (qtinst) {
 
593
                    if (qtinst->getObject()) {
 
594
                        qConvDebug() << "found instance, with object:" << (void*) qtinst->getObject();
 
595
                        ret = QVariant::fromValue((void *)qtinst->getObject());
 
596
                        qConvDebug() << ret;
 
597
                        dist = 0;
 
598
                    } else {
 
599
                        qConvDebug() << "can't convert deleted qobject";
 
600
                    }
 
601
                } else {
 
602
                    qConvDebug() << "wasn't a qtinstance";
 
603
                }
 
604
            } else if (type == Null) {
 
605
                ret = QVariant::fromValue((void*)0);
 
606
                dist = 0;
 
607
            } else if (type == Number) {
 
608
                // I don't think that converting a double to a pointer is a wise
 
609
                // move.  Except maybe 0.
 
610
                qConvDebug() << "got number for void * - not converting, seems unsafe:" << JSValueToNumber(context, value, 0);
 
611
            } else {
 
612
                qConvDebug() << "void* - unhandled type" << type;
 
613
            }
 
614
            break;
 
615
 
 
616
        default:
 
617
            // Non const type ids
 
618
            if (hint == (QMetaType::Type) qMetaTypeId<QObjectList>()) {
 
619
                ret = QVariant::fromValue(convertToList<QObject*>(context, type, object, value, &dist, exception));
 
620
                break;
 
621
            }
 
622
            if (hint == (QMetaType::Type) qMetaTypeId<QList<int> >()) {
 
623
                ret = QVariant::fromValue(convertToList<int>(context, type, object, value, &dist, exception));
 
624
                break;
 
625
            }
 
626
            if (QtPixmapRuntime::canHandle(static_cast<QMetaType::Type>(hint))) {
 
627
                ret = QtPixmapRuntime::toQt(context, object, static_cast<QMetaType::Type>(hint), exception);
 
628
            } else if (customRuntimeConversions()->contains(hint)) {
 
629
                ret = customRuntimeConversions()->value(hint).toVariantFunc(toJS(object), &dist, visitedObjects);
 
630
                if (dist == 0)
 
631
                    break;
 
632
            } else if (hint == (QMetaType::Type) qMetaTypeId<QVariant>()) {
 
633
                if (JSValueIsNull(context, value) || JSValueIsUndefined(context, value)) {
 
634
                    if (distance)
 
635
                        *distance = 1;
 
636
                    return QVariant();
 
637
                }
 
638
                if (type == Object) {
 
639
                    // Since we haven't really visited this object yet, we remove it
 
640
                    visitedObjects->remove(object);
 
641
                }
 
642
 
 
643
                // And then recurse with the autodetect flag
 
644
                ret = convertValueToQVariant(context, value, QMetaType::Void, distance, visitedObjects, recursionLimit, exception);
 
645
                dist = 10;
 
646
                break;
 
647
            }
 
648
 
 
649
            dist = 10;
 
650
            break;
 
651
    }
 
652
 
 
653
    if (!ret.isValid())
 
654
        dist = -1;
 
655
    if (distance)
 
656
        *distance = dist;
 
657
 
 
658
    return ret;
 
659
}
 
660
 
 
661
QVariant convertValueToQVariant(JSContextRef context, JSValueRef value, QMetaType::Type hint, int *distance, JSValueRef *exception)
 
662
{
 
663
    const int recursionLimit = 200;
 
664
    HashSet<JSObjectRef> visitedObjects;
 
665
    return convertValueToQVariant(context, value, hint, distance, &visitedObjects, recursionLimit, exception);
 
666
}
 
667
 
 
668
JSValueRef convertQVariantToValue(JSContextRef context, PassRefPtr<RootObject> root, const QVariant& variant, JSValueRef *exception)
 
669
{
 
670
    // Variants with QObject * can be isNull but not a null pointer
 
671
    // An empty QString variant is also null
 
672
    QMetaType::Type type = (QMetaType::Type) variant.userType();
 
673
 
 
674
    qConvDebug() << "convertQVariantToValue: metatype:" << type << ", isnull: " << variant.isNull();
 
675
    if (variant.isNull() &&
 
676
        !QMetaType::typeFlags(type).testFlag(QMetaType::PointerToQObject) &&
 
677
        type != QMetaType::VoidStar &&
 
678
        type != QMetaType::QString) {
 
679
        return JSValueMakeNull(context);
 
680
    }
 
681
 
 
682
    if (type == QMetaType::Bool)
 
683
        return JSValueMakeBoolean(context, variant.toBool());
 
684
 
 
685
    if (type == QMetaType::Int ||
 
686
        type == QMetaType::UInt ||
 
687
        type == QMetaType::Long ||
 
688
        type == QMetaType::ULong ||
 
689
        type == QMetaType::LongLong ||
 
690
        type == QMetaType::ULongLong ||
 
691
        type == QMetaType::Short ||
 
692
        type == QMetaType::UShort ||
 
693
        type == QMetaType::Float ||
 
694
        type == QMetaType::Double)
 
695
        return JSValueMakeNumber(context, variant.toDouble());
 
696
 
 
697
    if (type == QMetaType::QDateTime ||
 
698
        type == QMetaType::QDate ||
 
699
        type == QMetaType::QTime) {
 
700
 
 
701
        QDate date = QDate::currentDate();
 
702
        QTime time(0,0,0); // midnight
 
703
 
 
704
        if (type == QMetaType::QDate)
 
705
            date = variant.value<QDate>();
 
706
        else if (type == QMetaType::QTime)
 
707
            time = variant.value<QTime>();
 
708
        else {
 
709
            QDateTime dt = variant.value<QDateTime>().toLocalTime();
 
710
            date = dt.date();
 
711
            time = dt.time();
 
712
        }
 
713
 
 
714
        // Dates specified this way are in local time (we convert DateTimes above)
 
715
        const JSValueRef arguments[] = {
 
716
            JSValueMakeNumber(context, date.year()),
 
717
            JSValueMakeNumber(context, date.month() - 1),
 
718
            JSValueMakeNumber(context, date.day()),
 
719
            JSValueMakeNumber(context, time.hour()),
 
720
            JSValueMakeNumber(context, time.minute()),
 
721
            JSValueMakeNumber(context, time.second()),
 
722
            JSValueMakeNumber(context, time.msec())
 
723
        };
 
724
        return JSObjectMakeDate(context, 7, arguments, exception);
 
725
    }
 
726
 
 
727
    if (type == QMetaType::QByteArray) {
 
728
        QByteArray qtByteArray = variant.value<QByteArray>();
 
729
        WTF::RefPtr<WTF::Uint8ClampedArray> wtfByteArray = WTF::Uint8ClampedArray::createUninitialized(qtByteArray.length());
 
730
        memcpy(wtfByteArray->data(), qtByteArray.constData(), qtByteArray.length());
 
731
        ExecState* exec = toJS(context);
 
732
        return toRef(exec, toJS(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), wtfByteArray.get()));
 
733
    }
 
734
 
 
735
    if (QMetaType::typeFlags(type).testFlag(QMetaType::PointerToQObject)) {
 
736
        QObject* obj = variant.value<QObject*>();
 
737
        if (!obj)
 
738
            return JSValueMakeNull(context);
 
739
        ExecState* exec = toJS(context);
 
740
        return toRef(exec, QtInstance::getQtInstance(obj, root, QtInstance::QtOwnership)->createRuntimeObject(exec));
 
741
    }
 
742
 
 
743
    if (QtPixmapRuntime::canHandle(static_cast<QMetaType::Type>(variant.type())))
 
744
        return QtPixmapRuntime::toJS(context, variant, exception);
 
745
 
 
746
    if (customRuntimeConversions()->contains(type)) {
 
747
        if (!root->globalObject()->inherits(&JSDOMWindow::s_info))
 
748
            return JSValueMakeUndefined(context);
 
749
 
 
750
        Document* document = (static_cast<JSDOMWindow*>(root->globalObject()))->impl()->document();
 
751
        if (!document)
 
752
            return JSValueMakeUndefined(context);
 
753
        ExecState* exec = toJS(context);
 
754
        return toRef(exec, customRuntimeConversions()->value(type).toJSValueFunc(exec, toJSDOMGlobalObject(document, exec), variant));
 
755
    }
 
756
 
 
757
    if (type == QMetaType::QVariantMap) {
 
758
        // create a new object, and stuff properties into it
 
759
        JSObjectRef ret = JSObjectMake(context, 0, 0);
 
760
        QVariantMap map = variant.value<QVariantMap>();
 
761
        QVariantMap::const_iterator i = map.constBegin();
 
762
        while (i != map.constEnd()) {
 
763
            QString s = i.key();
 
764
            JSStringRef propertyName = JSStringCreateWithCharacters(reinterpret_cast<const JSChar*>(s.constData()), s.length());
 
765
            JSValueRef propertyValue = convertQVariantToValue(context, root.get(), i.value(), /*ignored exception*/0);
 
766
            if (propertyValue)
 
767
                JSObjectSetProperty(context, ret, propertyName, propertyValue, kJSPropertyAttributeNone, /*ignored exception*/0);
 
768
            JSStringRelease(propertyName);
 
769
            ++i;
 
770
        }
 
771
 
 
772
        return ret;
 
773
    }
 
774
 
 
775
    // List types
 
776
    if (type == QMetaType::QVariantList) {
 
777
        // ### TODO: Could use special array class that lazily converts.
 
778
        // See https://bugs.webkit.org/show_bug.cgi?id=94691
 
779
        QVariantList vl = variant.toList();
 
780
        JSObjectRef array = JSObjectMakeArray(context, 0, 0, exception);
 
781
        if (exception && *exception)
 
782
            return array;
 
783
        for (int i = 0; i < vl.count(); ++i) {
 
784
            JSValueRef property = convertQVariantToValue(context, root.get(), vl.at(i), /*ignored exception*/0);
 
785
            if (property)
 
786
                JSObjectSetPropertyAtIndex(context, array, i, property, /*ignored exception*/0);
 
787
        }
 
788
        return array;
 
789
    } else if (type == QMetaType::QStringList) {
 
790
        QStringList sl = variant.value<QStringList>();
 
791
        JSObjectRef array = JSObjectMakeArray(context, 0, 0, exception);
 
792
        for (int i = 0; i < sl.count(); ++i) {
 
793
            const QString& s = sl.at(i);
 
794
            JSStringRef jsString = JSStringCreateWithCharacters(reinterpret_cast<const JSChar*>(s.constData()), s.length());
 
795
            JSObjectSetPropertyAtIndex(context, array, i, JSValueMakeString(context, jsString), /*ignored exception*/0);
 
796
            JSStringRelease(jsString);
 
797
        }
 
798
        return array;
 
799
    } else if (type == static_cast<QMetaType::Type>(qMetaTypeId<QObjectList>())) {
 
800
        QObjectList ol = variant.value<QObjectList>();
 
801
        JSObjectRef array = JSObjectMakeArray(context, 0, 0, exception);
 
802
        ExecState* exec = toJS(context);
 
803
        for (int i = 0; i < ol.count(); ++i) {
 
804
            JSValueRef jsObject = toRef(exec, QtInstance::getQtInstance(ol.at(i), root, QtInstance::QtOwnership)->createRuntimeObject(exec));
 
805
            JSObjectSetPropertyAtIndex(context, array, i, jsObject, /*ignored exception*/0);
 
806
        }
 
807
        return array;
 
808
    } else if (type == static_cast<QMetaType::Type>(qMetaTypeId<QList<int> >())) {
 
809
        QList<int> il = variant.value<QList<int> >();
 
810
        JSObjectRef array = JSObjectMakeArray(context, 0, 0, exception);
 
811
        for (int i = 0; i < il.count(); ++i)
 
812
            JSObjectSetPropertyAtIndex(context, array, i, JSValueMakeNumber(context, il.at(i)), /*ignored exception*/0);
 
813
        return array;
 
814
    }
 
815
 
 
816
    if (type == (QMetaType::Type)qMetaTypeId<QVariant>()) {
 
817
        QVariant real = variant.value<QVariant>();
 
818
        qConvDebug() << "real variant is:" << real;
 
819
        return convertQVariantToValue(context, root.get(), real, exception);
 
820
    }
 
821
 
 
822
    qConvDebug() << "fallback path for" << variant << variant.userType();
 
823
 
 
824
    QString string = variant.toString();
 
825
    JSStringRef jsstring = JSStringCreateWithCharacters(reinterpret_cast<const JSChar*>(string.constData()), string.length());
 
826
    JSValueRef value = JSValueMakeString(context, jsstring);
 
827
    JSStringRelease(jsstring);
 
828
    return value;
 
829
}
 
830
 
 
831
// Type conversion metadata (from QtScript originally)
 
832
class QtMethodMatchType
 
833
{
 
834
public:
 
835
    enum Kind {
 
836
        Invalid,
 
837
        Variant,
 
838
        MetaType,
 
839
        Unresolved,
 
840
        MetaEnum
 
841
    };
 
842
 
 
843
 
 
844
    QtMethodMatchType()
 
845
        : m_kind(Invalid) { }
 
846
 
 
847
    Kind kind() const
 
848
    { return m_kind; }
 
849
 
 
850
    QMetaType::Type typeId() const;
 
851
 
 
852
    bool isValid() const
 
853
    { return (m_kind != Invalid); }
 
854
 
 
855
    bool isVariant() const
 
856
    { return (m_kind == Variant); }
 
857
 
 
858
    bool isMetaType() const
 
859
    { return (m_kind == MetaType); }
 
860
 
 
861
    bool isUnresolved() const
 
862
    { return (m_kind == Unresolved); }
 
863
 
 
864
    bool isMetaEnum() const
 
865
    { return (m_kind == MetaEnum); }
 
866
 
 
867
    QByteArray name() const;
 
868
 
 
869
    int enumeratorIndex() const
 
870
    { Q_ASSERT(isMetaEnum()); return m_typeId; }
 
871
 
 
872
    static QtMethodMatchType variant()
 
873
    { return QtMethodMatchType(Variant); }
 
874
 
 
875
    static QtMethodMatchType metaType(int typeId, const QByteArray &name)
 
876
    { return QtMethodMatchType(MetaType, typeId, name); }
 
877
 
 
878
    static QtMethodMatchType metaEnum(int enumIndex, const QByteArray &name)
 
879
    { return QtMethodMatchType(MetaEnum, enumIndex, name); }
 
880
 
 
881
    static QtMethodMatchType unresolved(const QByteArray &name)
 
882
    { return QtMethodMatchType(Unresolved, /*typeId=*/0, name); }
 
883
 
 
884
private:
 
885
    QtMethodMatchType(Kind kind, int typeId = 0, const QByteArray &name = QByteArray())
 
886
        : m_kind(kind), m_typeId(typeId), m_name(name) { }
 
887
 
 
888
    Kind m_kind;
 
889
    int m_typeId;
 
890
    QByteArray m_name;
 
891
};
 
892
 
 
893
QMetaType::Type QtMethodMatchType::typeId() const
 
894
{
 
895
    if (isVariant())
 
896
        return (QMetaType::Type) QMetaType::type("QVariant");
 
897
    return (QMetaType::Type) (isMetaEnum() ? QMetaType::Int : m_typeId);
 
898
}
 
899
 
 
900
QByteArray QtMethodMatchType::name() const
 
901
{
 
902
    if (!m_name.isEmpty())
 
903
        return m_name;
 
904
    else if (m_kind == Variant)
 
905
        return "QVariant";
 
906
    return QByteArray();
 
907
}
 
908
 
 
909
struct QtMethodMatchData
 
910
{
 
911
    int matchDistance;
 
912
    int index;
 
913
    QVector<QtMethodMatchType> types;
 
914
    QVarLengthArray<QVariant, 10> args;
 
915
 
 
916
    QtMethodMatchData(int dist, int idx, QVector<QtMethodMatchType> typs,
 
917
                                const QVarLengthArray<QVariant, 10> &as)
 
918
        : matchDistance(dist), index(idx), types(typs), args(as) { }
 
919
    QtMethodMatchData()
 
920
        : index(-1) { }
 
921
 
 
922
    bool isValid() const
 
923
    { return (index != -1); }
 
924
 
 
925
    int firstUnresolvedIndex() const
 
926
    {
 
927
        for (int i=0; i < types.count(); i++) {
 
928
            if (types.at(i).isUnresolved())
 
929
                return i;
 
930
        }
 
931
        return -1;
 
932
    }
 
933
};
 
934
 
 
935
static int indexOfMetaEnum(const QMetaObject *meta, const QByteArray &str)
 
936
{
 
937
    QByteArray scope;
 
938
    QByteArray name;
 
939
    int scopeIdx = str.indexOf("::");
 
940
    if (scopeIdx != -1) {
 
941
        scope = str.left(scopeIdx);
 
942
        name = str.mid(scopeIdx + 2);
 
943
    } else {
 
944
        name = str;
 
945
    }
 
946
    for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
 
947
        QMetaEnum m = meta->enumerator(i);
 
948
        if ((m.name() == name)/* && (scope.isEmpty() || (m.scope() == scope))*/)
 
949
            return i;
 
950
    }
 
951
    return -1;
 
952
}
 
953
 
 
954
// Helper function for resolving methods
 
955
// Largely based on code in QtScript for compatibility reasons
 
956
static int findMethodIndex(JSContextRef context,
 
957
                           const QMetaObject* meta,
 
958
                           const QByteArray& signature,
 
959
                           int argumentCount,
 
960
                           const JSValueRef arguments[],
 
961
                           bool allowPrivate,
 
962
                           QVarLengthArray<QVariant, 10> &vars,
 
963
                           void** vvars,
 
964
                           JSValueRef* exception)
 
965
{
 
966
    QList<int> matchingIndices;
 
967
 
 
968
    bool overloads = !signature.contains('(');
 
969
 
 
970
    int count = meta->methodCount();
 
971
    for (int i = count - 1; i >= 0; --i) {
 
972
        const QMetaMethod m = meta->method(i);
 
973
 
 
974
        // Don't choose private methods
 
975
        if (m.access() == QMetaMethod::Private && !allowPrivate)
 
976
            continue;
 
977
 
 
978
        // try and find all matching named methods
 
979
        if (!overloads && m.methodSignature() == signature)
 
980
            matchingIndices.append(i);
 
981
        else if (overloads && m.name() == signature)
 
982
            matchingIndices.append(i);
 
983
    }
 
984
 
 
985
    int chosenIndex = -1;
 
986
    QVector<QtMethodMatchType> chosenTypes;
 
987
 
 
988
    QVarLengthArray<QVariant, 10> args;
 
989
    QVector<QtMethodMatchData> candidates;
 
990
    QVector<QtMethodMatchData> unresolved;
 
991
    QVector<int> tooFewArgs;
 
992
    QVector<int> conversionFailed;
 
993
 
 
994
    foreach(int index, matchingIndices) {
 
995
        QMetaMethod method = meta->method(index);
 
996
 
 
997
        QVector<QtMethodMatchType> types;
 
998
        bool unresolvedTypes = false;
 
999
 
 
1000
        // resolve return type
 
1001
        QByteArray returnTypeName = method.typeName();
 
1002
        int rtype = method.returnType();
 
1003
        if (rtype == QMetaType::UnknownType) {
 
1004
            if (returnTypeName.endsWith('*')) {
 
1005
                types.append(QtMethodMatchType::metaType(QMetaType::VoidStar, returnTypeName));
 
1006
            } else {
 
1007
                int enumIndex = indexOfMetaEnum(meta, returnTypeName);
 
1008
                if (enumIndex != -1)
 
1009
                    types.append(QtMethodMatchType::metaEnum(enumIndex, returnTypeName));
 
1010
                else {
 
1011
                    unresolvedTypes = true;
 
1012
                    types.append(QtMethodMatchType::unresolved(returnTypeName));
 
1013
                }
 
1014
            }
 
1015
        } else {
 
1016
            if (rtype == QMetaType::QVariant)
 
1017
                types.append(QtMethodMatchType::variant());
 
1018
            else
 
1019
                types.append(QtMethodMatchType::metaType(rtype, returnTypeName));
 
1020
        }
 
1021
 
 
1022
        // resolve argument types
 
1023
        QList<QByteArray> parameterTypeNames = method.parameterTypes();
 
1024
        for (int i = 0; i < parameterTypeNames.count(); ++i) {
 
1025
            QByteArray argTypeName = parameterTypeNames.at(i);
 
1026
            int atype = method.parameterType(i);
 
1027
            if (atype == QMetaType::UnknownType) {
 
1028
                int enumIndex = indexOfMetaEnum(meta, argTypeName);
 
1029
                if (enumIndex != -1)
 
1030
                    types.append(QtMethodMatchType::metaEnum(enumIndex, argTypeName));
 
1031
                else {
 
1032
                    unresolvedTypes = true;
 
1033
                    types.append(QtMethodMatchType::unresolved(argTypeName));
 
1034
                }
 
1035
            } else {
 
1036
                if (atype == QMetaType::QVariant)
 
1037
                    types.append(QtMethodMatchType::variant());
 
1038
                else
 
1039
                    types.append(QtMethodMatchType::metaType(atype, argTypeName));
 
1040
            }
 
1041
        }
 
1042
 
 
1043
        // If the native method requires more arguments than what was passed from JavaScript
 
1044
        if (argumentCount + 1 < static_cast<unsigned>(types.count())) {
 
1045
            qMatchDebug() << "Match:too few args for" << method.methodSignature();
 
1046
            tooFewArgs.append(index);
 
1047
            continue;
 
1048
        }
 
1049
 
 
1050
        if (unresolvedTypes) {
 
1051
            qMatchDebug() << "Match:unresolved arg types for" << method.methodSignature();
 
1052
            // remember it so we can give an error message later, if necessary
 
1053
            unresolved.append(QtMethodMatchData(/*matchDistance=*/INT_MAX, index,
 
1054
                                                   types, QVarLengthArray<QVariant, 10>()));
 
1055
            continue;
 
1056
        }
 
1057
 
 
1058
        // Now convert arguments
 
1059
        if (args.count() != types.count())
 
1060
            args.resize(types.count());
 
1061
 
 
1062
        QtMethodMatchType retType = types[0];
 
1063
        if (retType.typeId() != QMetaType::Void)
 
1064
            args[0] = QVariant(retType.typeId(), (void *)0); // the return value
 
1065
 
 
1066
        bool converted = true;
 
1067
        int matchDistance = 0;
 
1068
        for (unsigned i = 0; converted && i + 1 < static_cast<unsigned>(types.count()); ++i) {
 
1069
            JSValueRef arg = i < argumentCount ? arguments[i] : JSValueMakeUndefined(context);
 
1070
 
 
1071
            int argdistance = -1;
 
1072
            QVariant v = convertValueToQVariant(context, arg, types.at(i+1).typeId(), &argdistance, exception);
 
1073
            if (argdistance >= 0) {
 
1074
                matchDistance += argdistance;
 
1075
                args[i+1] = v;
 
1076
            } else {
 
1077
                qMatchDebug() << "failed to convert argument " << i << "type" << types.at(i+1).typeId() << QMetaType::typeName(types.at(i+1).typeId());
 
1078
                converted = false;
 
1079
            }
 
1080
        }
 
1081
 
 
1082
        qMatchDebug() << "Match: " << method.methodSignature() << (converted ? "converted":"failed to convert") << "distance " << matchDistance;
 
1083
 
 
1084
        if (converted) {
 
1085
            if ((argumentCount + 1 == static_cast<unsigned>(types.count()))
 
1086
                && (matchDistance == 0)) {
 
1087
                // perfect match, use this one
 
1088
                chosenIndex = index;
 
1089
                break;
 
1090
            }
 
1091
            QtMethodMatchData currentMatch(matchDistance, index, types, args);
 
1092
            if (candidates.isEmpty())
 
1093
                candidates.append(currentMatch);
 
1094
            else {
 
1095
                QtMethodMatchData bestMatchSoFar = candidates.at(0);
 
1096
                if ((args.count() > bestMatchSoFar.args.count())
 
1097
                    || ((args.count() == bestMatchSoFar.args.count())
 
1098
                    && (matchDistance <= bestMatchSoFar.matchDistance)))
 
1099
                    candidates.prepend(currentMatch);
 
1100
                else
 
1101
                    candidates.append(currentMatch);
 
1102
            }
 
1103
        } else {
 
1104
            conversionFailed.append(index);
 
1105
        }
 
1106
 
 
1107
        if (!overloads)
 
1108
            break;
 
1109
    }
 
1110
 
 
1111
    if (chosenIndex == -1 && candidates.count() == 0) {
 
1112
        // No valid functions at all - format an error message
 
1113
        if (!conversionFailed.isEmpty()) {
 
1114
            QString message = QString::fromLatin1("incompatible type of argument(s) in call to %0(); candidates were\n")
 
1115
                              .arg(QString::fromLatin1(signature));
 
1116
            for (int i = 0; i < conversionFailed.size(); ++i) {
 
1117
                if (i > 0)
 
1118
                    message += QLatin1String("\n");
 
1119
                QMetaMethod mtd = meta->method(conversionFailed.at(i));
 
1120
                message += QString::fromLatin1("    %0").arg(QString::fromLatin1(mtd.methodSignature()));
 
1121
            }
 
1122
            setException(context, exception, message);
 
1123
        } else if (!unresolved.isEmpty()) {
 
1124
            QtMethodMatchData argsInstance = unresolved.first();
 
1125
            int unresolvedIndex = argsInstance.firstUnresolvedIndex();
 
1126
            Q_ASSERT(unresolvedIndex != -1);
 
1127
            QtMethodMatchType unresolvedType = argsInstance.types.at(unresolvedIndex);
 
1128
            QString message = QString::fromLatin1("cannot call %0(): unknown type `%1'")
 
1129
                .arg(QString::fromLatin1(signature))
 
1130
                .arg(QLatin1String(unresolvedType.name()));
 
1131
            setException(context, exception, message);
 
1132
        } else {
 
1133
            QString message = QString::fromLatin1("too few arguments in call to %0(); candidates are\n")
 
1134
                              .arg(QString::fromLatin1(signature));
 
1135
            for (int i = 0; i < tooFewArgs.size(); ++i) {
 
1136
                if (i > 0)
 
1137
                    message += QLatin1String("\n");
 
1138
                QMetaMethod mtd = meta->method(tooFewArgs.at(i));
 
1139
                message += QString::fromLatin1("    %0").arg(QString::fromLatin1(mtd.methodSignature()));
 
1140
            }
 
1141
            setException(context, exception, message);
 
1142
        }
 
1143
    }
 
1144
 
 
1145
    if (chosenIndex == -1 && candidates.count() > 0) {
 
1146
        QtMethodMatchData bestMatch = candidates.at(0);
 
1147
        if ((candidates.size() > 1)
 
1148
            && (bestMatch.args.count() == candidates.at(1).args.count())
 
1149
            && (bestMatch.matchDistance == candidates.at(1).matchDistance)) {
 
1150
            // ambiguous call
 
1151
            QString message = QString::fromLatin1("ambiguous call of overloaded function %0(); candidates were\n")
 
1152
                                .arg(QLatin1String(signature));
 
1153
            for (int i = 0; i < candidates.size(); ++i) {
 
1154
                // Only candidate for overload if argument count and match distance is same as best match
 
1155
                if (candidates.at(i).args.count() == bestMatch.args.count()
 
1156
                    || candidates.at(i).matchDistance == bestMatch.matchDistance) {
 
1157
                    if (i > 0)
 
1158
                        message += QLatin1String("\n");
 
1159
                    QMetaMethod mtd = meta->method(candidates.at(i).index);
 
1160
                    message += QString::fromLatin1("    %0").arg(QString::fromLatin1(mtd.methodSignature()));
 
1161
                }
 
1162
            }
 
1163
            setException(context, exception, message);
 
1164
        } else {
 
1165
            chosenIndex = bestMatch.index;
 
1166
            args = bestMatch.args;
 
1167
        }
 
1168
    }
 
1169
 
 
1170
    if (chosenIndex != -1) {
 
1171
        /* Copy the stuff over */
 
1172
        int i;
 
1173
        vars.resize(args.count());
 
1174
        for (i=0; i < args.count(); i++) {
 
1175
            vars[i] = args[i];
 
1176
            vvars[i] = vars[i].data();
 
1177
        }
 
1178
    }
 
1179
 
 
1180
    return chosenIndex;
 
1181
}
 
1182
 
 
1183
// Signals are not fuzzy matched as much as methods
 
1184
static int findSignalIndex(const QMetaObject* meta, int initialIndex, QByteArray signature)
 
1185
{
 
1186
    int index = initialIndex;
 
1187
    QMetaMethod method = meta->method(index);
 
1188
    bool overloads = !signature.contains('(');
 
1189
    if (overloads && (method.attributes() & QMetaMethod::Cloned)) {
 
1190
        // find the most general method
 
1191
        do {
 
1192
            method = meta->method(--index);
 
1193
        } while (method.attributes() & QMetaMethod::Cloned);
 
1194
    }
 
1195
    return index;
 
1196
}
 
1197
 
 
1198
static JSClassRef prototypeForSignalsAndSlots()
 
1199
{
 
1200
    static JSClassDefinition classDef = {
 
1201
        0, kJSClassAttributeNoAutomaticPrototype, 0, 0, 0, 0,
 
1202
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 
1203
    };
 
1204
    static JSClassRef cls = JSClassCreate(&classDef);
 
1205
    return cls;
 
1206
}
 
1207
 
 
1208
QtRuntimeMethod::QtRuntimeMethod(JSContextRef ctx, QObject* object, const QByteArray& identifier, int index, int flags, QtInstance* instance)
 
1209
    : m_object(object)
 
1210
    , m_identifier(identifier)
 
1211
    , m_index(index)
 
1212
    , m_flags(flags)
 
1213
    , m_instance(instance)
 
1214
{
 
1215
}
 
1216
 
 
1217
QtRuntimeMethod::~QtRuntimeMethod()
 
1218
{
 
1219
}
 
1220
 
 
1221
JSValueRef QtRuntimeMethod::call(JSContextRef context, JSObjectRef function, JSObjectRef /*thisObject*/, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
 
1222
{
 
1223
    QtRuntimeMethod* d = toRuntimeMethod(context, function);
 
1224
    if (!d) {
 
1225
        setException(context, exception, QStringLiteral("cannot call function of deleted runtime method"));
 
1226
        return JSValueMakeUndefined(context);
 
1227
    }
 
1228
    QObject* obj = d->m_object;
 
1229
 
 
1230
    if (!obj) {
 
1231
        setException(context, exception, QStringLiteral("cannot call function of deleted QObject"));
 
1232
        return JSValueMakeUndefined(context);
 
1233
    }
 
1234
 
 
1235
    // Allow for maximum of 10 arguments and size stack arrays accordingly.
 
1236
    if (argumentCount > 10)
 
1237
        return JSValueMakeUndefined(context);
 
1238
 
 
1239
    QVarLengthArray<QVariant, 10> vargs;
 
1240
    void* qargs[11];
 
1241
 
 
1242
    int methodIndex = findMethodIndex(context, obj->metaObject(), d->m_identifier,  argumentCount, arguments,
 
1243
                                      (d->m_flags & AllowPrivate), vargs, (void **)qargs, exception);
 
1244
 
 
1245
    if (QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, methodIndex, qargs) >= 0)
 
1246
        return JSValueMakeUndefined(context);
 
1247
 
 
1248
    if (vargs.size() > 0 && vargs[0].isValid())
 
1249
        return convertQVariantToValue(context, d->m_instance->rootObject(), vargs[0], exception);
 
1250
 
 
1251
    return JSValueMakeUndefined(context);
 
1252
}
 
1253
 
 
1254
JSValueRef QtRuntimeMethod::connect(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
 
1255
{
 
1256
    return connectOrDisconnect(context, function, thisObject, argumentCount, arguments, exception, true);
 
1257
}
 
1258
 
 
1259
JSValueRef QtRuntimeMethod::disconnect(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
 
1260
{
 
1261
    return connectOrDisconnect(context, function, thisObject, argumentCount, arguments, exception, false);
 
1262
}
 
1263
 
 
1264
JSObjectRef QtRuntimeMethod::jsObjectRef(JSContextRef context, JSValueRef* exception)
 
1265
{
 
1266
    if (m_jsObject)
 
1267
        return toRef(m_jsObject.get());
 
1268
 
 
1269
    static JSStringRef connectStr = JSStringCreateWithUTF8CString("connect");
 
1270
    static JSStringRef disconnectStr = JSStringCreateWithUTF8CString("disconnect");
 
1271
    JSRetainPtr<JSStringRef> actualNameStr(Adopt, JSStringCreateWithUTF8CString(m_identifier.constData()));
 
1272
 
 
1273
    JSObjectRef object = JSObjectMakeFunctionWithCallback(context, actualNameStr.get(), call);
 
1274
 
 
1275
    JSObjectRef generalFunctionProto = JSValueToObject(context, JSObjectGetPrototype(context, object), 0);
 
1276
    JSObjectRef runtimeMethodProto = JSObjectMake(context, prototypeForSignalsAndSlots(), this);
 
1277
    JSObjectSetPrototype(context, runtimeMethodProto, generalFunctionProto);
 
1278
 
 
1279
    JSObjectSetPrototype(context, object, runtimeMethodProto);
 
1280
 
 
1281
    JSObjectRef connectFunction = JSObjectMakeFunctionWithCallback(context, connectStr, connect);
 
1282
    JSObjectSetPrototype(context, connectFunction, runtimeMethodProto);
 
1283
 
 
1284
    JSObjectRef disconnectFunction = JSObjectMakeFunctionWithCallback(context, disconnectStr, disconnect);
 
1285
    JSObjectSetPrototype(context, disconnectFunction, runtimeMethodProto);
 
1286
 
 
1287
    const JSPropertyAttributes attributes = kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete;
 
1288
    JSObjectSetProperty(context, object, connectStr, connectFunction, attributes, exception);
 
1289
    JSObjectSetProperty(context, object, disconnectStr, disconnectFunction, attributes, exception);
 
1290
 
 
1291
    m_jsObject = PassWeak<JSObject>(toJS(object));
 
1292
 
 
1293
    return object;
 
1294
}
 
1295
 
 
1296
QtRuntimeMethod* QtRuntimeMethod::toRuntimeMethod(JSContextRef context, JSObjectRef object)
 
1297
{
 
1298
    JSObjectRef proto = JSValueToObject(context, JSObjectGetPrototype(context, object), 0);
 
1299
    if (!proto)
 
1300
        return 0;
 
1301
    if (!JSValueIsObjectOfClass(context, proto, prototypeForSignalsAndSlots()))
 
1302
        return 0;
 
1303
    return static_cast<QtRuntimeMethod*>(JSObjectGetPrivate(proto));
 
1304
}
 
1305
 
 
1306
JSValueRef QtRuntimeMethod::connectOrDisconnect(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception, bool connect)
 
1307
{
 
1308
    QtRuntimeMethod* d = toRuntimeMethod(context, thisObject);
 
1309
    if (!d)
 
1310
        d = toRuntimeMethod(context, function);
 
1311
    if (!d) {
 
1312
        QString errorStr = QStringLiteral("QtMetaMethod.%1: Cannot connect to/from deleted QObject").arg(connect ?  QStringLiteral("connect") : QStringLiteral("disconnect"));
 
1313
        setException(context, exception, errorStr);
 
1314
        return JSValueMakeUndefined(context);
 
1315
    }
 
1316
 
 
1317
    QString functionName = connect ? QStringLiteral("connect") : QStringLiteral("disconnect");
 
1318
 
 
1319
    if (!argumentCount) {
 
1320
        QString errorStr = QStringLiteral("QtMetaMethod.%1: no arguments given").arg(connect ?  QStringLiteral("connect") : QStringLiteral("disconnect"));
 
1321
        setException(context, exception, errorStr);
 
1322
        return JSValueMakeUndefined(context);
 
1323
    }
 
1324
 
 
1325
    if ((!(d->m_flags & QtRuntimeMethod::MethodIsSignal))) {
 
1326
        setException(context, exception, QStringLiteral("QtMetaMethod.%3: %1::%2() is not a signal").arg(QString::fromUtf8(d->m_object.data()->metaObject()->className())).arg(QString::fromLatin1(d->m_identifier)).arg(functionName));
 
1327
        return JSValueMakeUndefined(context);
 
1328
    }
 
1329
 
 
1330
    QObject* sender = d->m_object.data();
 
1331
 
 
1332
    if (!sender) {
 
1333
        setException(context, exception, QStringLiteral("cannot call function of deleted QObject"));
 
1334
        return JSValueMakeUndefined(context);
 
1335
    }
 
1336
 
 
1337
    int signalIndex = findSignalIndex(sender->metaObject(), d->m_index, d->m_identifier);
 
1338
 
 
1339
    JSObjectRef targetObject = 0;
 
1340
    JSObjectRef targetFunction = 0;
 
1341
 
 
1342
    if (argumentCount == 1) {
 
1343
        if (!JSValueIsObject(context, arguments[0])) {
 
1344
            setException(context, exception, QStringLiteral("QtMetaMethod.%1: target is not a function").arg(functionName));
 
1345
            return JSValueMakeUndefined(context);
 
1346
        }
 
1347
        targetFunction = JSValueToObject(context, arguments[0], exception);
 
1348
 
 
1349
        // object.signal.connect(someFunction);
 
1350
        if (JSObjectIsFunction(context, targetFunction)) {
 
1351
            // object.signal.connect(otherObject.slot);
 
1352
            if (QtRuntimeMethod* targetMethod = toRuntimeMethod(context, targetFunction))
 
1353
                targetObject = toRef(QtInstance::getQtInstance(targetMethod->m_object.data(), d->m_instance->rootObject(), QtInstance::QtOwnership)->createRuntimeObject(toJS(context)));
 
1354
        } else
 
1355
            targetFunction = 0;
 
1356
    } else {
 
1357
        // object.signal.connect(object, someFunction);
 
1358
        targetObject = JSValueToObject(context, arguments[0], exception);
 
1359
        if (JSValueIsObject(context, arguments[1])) {
 
1360
            JSObjectRef obj = JSValueToObject(context, arguments[1], exception);
 
1361
            if (JSObjectIsFunction(context, obj))
 
1362
                targetFunction = obj;
 
1363
        }
 
1364
        if (!targetFunction) {
 
1365
            // Maybe the second argument is a string
 
1366
            JSValueRef conversionException = 0;
 
1367
            JSRetainPtr<JSStringRef> functionName(Adopt, JSValueToStringCopy(context, arguments[1], &conversionException));
 
1368
            if (functionName && !conversionException) {
 
1369
                JSValueRef functionProperty = JSObjectGetProperty(context, targetObject, functionName.get(), &conversionException);
 
1370
                if (!conversionException && functionProperty && JSValueIsObject(context, functionProperty)) {
 
1371
                    targetFunction = JSValueToObject(context, functionProperty, 0);
 
1372
                    if (!JSObjectIsFunction(context, targetFunction))
 
1373
                        targetFunction = 0;
 
1374
                }
 
1375
            }
 
1376
        }
 
1377
    }
 
1378
 
 
1379
    // object.signal.connect(someObject);
 
1380
    if (!targetFunction) {
 
1381
        QString message = QStringLiteral("QtMetaMethod.%1: target is not a function");
 
1382
        if (connect)
 
1383
            message = message.arg(QStringLiteral("connect"));
 
1384
        else
 
1385
            message = message.arg(QStringLiteral("disconnect"));
 
1386
        setException(context, exception, message);
 
1387
        return JSValueMakeUndefined(context);
 
1388
    }
 
1389
 
 
1390
    if (connect) {
 
1391
        // to connect, we need:
 
1392
        //  target object [from ctor]
 
1393
        //  target signal index etc. [from ctor]
 
1394
        //  receiver function [from arguments]
 
1395
        //  receiver this object [from arguments]
 
1396
 
 
1397
        QtConnectionObject* conn = new QtConnectionObject(context, QtInstance::getQtInstance(sender, d->m_instance->rootObject(), QtInstance::QtOwnership), signalIndex, targetObject, targetFunction);
 
1398
        bool ok = QMetaObject::connect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
 
1399
        if (!ok) {
 
1400
            delete conn;
 
1401
            QString msg = QString(QLatin1String("QtMetaMethod.connect: failed to connect to %1::%2()"))
 
1402
                    .arg(QLatin1String(sender->metaObject()->className()))
 
1403
                    .arg(QLatin1String(d->m_identifier));
 
1404
            setException(context, exception, msg);
 
1405
            return JSValueMakeUndefined(context);
 
1406
        }
 
1407
 
 
1408
        // Store connection
 
1409
        QtConnectionObject::connections.insert(sender, conn);
 
1410
 
 
1411
        return JSValueMakeUndefined(context);
 
1412
    }
 
1413
 
 
1414
    // Now to find our previous connection object.
 
1415
    QList<QtConnectionObject*> conns = QtConnectionObject::connections.values(sender);
 
1416
 
 
1417
    foreach (QtConnectionObject* conn, conns) {
 
1418
        // Is this the right connection?
 
1419
        if (!conn->match(context, sender, signalIndex, targetObject, targetFunction))
 
1420
            continue;
 
1421
 
 
1422
        // Yep, disconnect it
 
1423
        QMetaObject::disconnect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
 
1424
        delete conn; // this will also remove it from the map
 
1425
        return JSValueMakeUndefined(context);
 
1426
    }
 
1427
 
 
1428
    QString msg = QStringLiteral("QtMetaMethod.disconnect: failed to disconnect from %1::%2()")
 
1429
            .arg(QLatin1String(sender->metaObject()->className()))
 
1430
            .arg(QLatin1String(d->m_identifier));
 
1431
 
 
1432
    setException(context, exception, msg);
 
1433
    return JSValueMakeUndefined(context);
 
1434
}
 
1435
 
 
1436
// ===============
 
1437
 
 
1438
QMultiMap<QObject*, QtConnectionObject*> QtConnectionObject::connections;
 
1439
 
 
1440
QtConnectionObject::QtConnectionObject(JSContextRef context, PassRefPtr<QtInstance> senderInstance, int signalIndex, JSObjectRef receiver, JSObjectRef receiverFunction)
 
1441
    : QObject(senderInstance->getObject())
 
1442
    , m_context(JSContextGetGlobalContext(context))
 
1443
    , m_rootObject(senderInstance->rootObject())
 
1444
    , m_signalIndex(signalIndex)
 
1445
    , m_receiver(receiver)
 
1446
    , m_receiverFunction(receiverFunction)
 
1447
{
 
1448
    if (m_receiver)
 
1449
        JSValueProtect(m_context, m_receiver);
 
1450
    JSValueProtect(m_context, m_receiverFunction);
 
1451
}
 
1452
 
 
1453
QtConnectionObject::~QtConnectionObject()
 
1454
{
 
1455
    connections.remove(parent(), this);
 
1456
 
 
1457
    if (m_receiver)
 
1458
        JSValueUnprotect(m_context, m_receiver);
 
1459
    JSValueUnprotect(m_context, m_receiverFunction);
 
1460
}
 
1461
 
 
1462
// Begin moc-generated code -- modify with care! Check "HAND EDIT" parts
 
1463
struct qt_meta_stringdata_QtConnectionObject_t {
 
1464
    QByteArrayData data[3];
 
1465
    char stringdata[44];
 
1466
};
 
1467
#define QT_MOC_LITERAL(idx, ofs, len) { \
 
1468
    Q_REFCOUNT_INITIALIZE_STATIC, len, 0, 0, \
 
1469
    offsetof(qt_meta_stringdata_QtConnectionObject_t, stringdata) + ofs \
 
1470
        - idx * sizeof(QByteArrayData) \
 
1471
    }
 
1472
static const qt_meta_stringdata_QtConnectionObject_t qt_meta_stringdata_QtConnectionObject = {
 
1473
    {
 
1474
QT_MOC_LITERAL(0, 0, 33),
 
1475
QT_MOC_LITERAL(1, 34, 7),
 
1476
QT_MOC_LITERAL(2, 42, 0)
 
1477
    },
 
1478
    "JSC::Bindings::QtConnectionObject\0"
 
1479
    "execute\0\0"
 
1480
};
 
1481
#undef QT_MOC_LITERAL
 
1482
 
 
1483
static const uint qt_meta_data_QtConnectionObject[] = {
 
1484
 
 
1485
 // content:
 
1486
       7,       // revision
 
1487
       0,       // classname
 
1488
       0,    0, // classinfo
 
1489
       1,   14, // methods
 
1490
       0,    0, // properties
 
1491
       0,    0, // enums/sets
 
1492
       0,    0, // constructors
 
1493
       0,       // flags
 
1494
       0,       // signalCount
 
1495
 
 
1496
 // slots: name, argc, parameters, tag, flags
 
1497
       1,    0,   19,    2, 0x0a,
 
1498
 
 
1499
 // slots: parameters
 
1500
    QMetaType::Void,
 
1501
 
 
1502
       0        // eod
 
1503
};
 
1504
 
 
1505
void QtConnectionObject::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
 
1506
{
 
1507
    if (_c == QMetaObject::InvokeMetaMethod) {
 
1508
        Q_ASSERT(staticMetaObject.cast(_o));
 
1509
        QtConnectionObject *_t = static_cast<QtConnectionObject *>(_o);
 
1510
        switch (_id) {
 
1511
        case 0: _t->execute(_a); break; // HAND EDIT: add _a parameter
 
1512
        default: ;
 
1513
        }
 
1514
    }
 
1515
}
 
1516
 
 
1517
const QMetaObject QtConnectionObject::staticMetaObject = {
 
1518
    { &QObject::staticMetaObject, qt_meta_stringdata_QtConnectionObject.data,
 
1519
      qt_meta_data_QtConnectionObject, qt_static_metacall, 0, 0 }
 
1520
};
 
1521
 
 
1522
const QMetaObject *QtConnectionObject::metaObject() const
 
1523
{
 
1524
    return &staticMetaObject;
 
1525
}
 
1526
 
 
1527
void *QtConnectionObject::qt_metacast(const char *_clname)
 
1528
{
 
1529
    if (!_clname) return 0;
 
1530
    if (!strcmp(_clname, qt_meta_stringdata_QtConnectionObject.stringdata))
 
1531
        return static_cast<void*>(const_cast<QtConnectionObject*>(this));
 
1532
    return QObject::qt_metacast(_clname);
 
1533
}
 
1534
 
 
1535
int QtConnectionObject::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
 
1536
{
 
1537
    _id = QObject::qt_metacall(_c, _id, _a);
 
1538
    if (_id < 0)
 
1539
        return _id;
 
1540
    if (_c == QMetaObject::InvokeMetaMethod) {
 
1541
        if (_id < 1)
 
1542
            qt_static_metacall(this, _c, _id, _a);
 
1543
        _id -= 1;
 
1544
    }
 
1545
    return _id;
 
1546
}
 
1547
// End of moc-generated code
 
1548
 
 
1549
void QtConnectionObject::execute(void** argv)
 
1550
{
 
1551
    QObject* sender = parent();
 
1552
    const QMetaObject* meta = sender->metaObject();
 
1553
    const QMetaMethod method = meta->method(m_signalIndex);
 
1554
 
 
1555
    JSValueRef* ignoredException = 0;
 
1556
    JSRetainPtr<JSStringRef> lengthProperty(JSStringCreateWithUTF8CString("length"));
 
1557
    int receiverLength = int(JSValueToNumber(m_context, JSObjectGetProperty(m_context, m_receiverFunction, lengthProperty.get(), ignoredException), ignoredException));
 
1558
    int argc = qMax(method.parameterCount(), receiverLength);
 
1559
    WTF::Vector<JSValueRef> args(argc);
 
1560
 
 
1561
    for (int i = 0; i < argc; i++) {
 
1562
        int argType = method.parameterType(i);
 
1563
        args[i] = convertQVariantToValue(m_context, m_rootObject, QVariant(argType, argv[i+1]), ignoredException);
 
1564
    }
 
1565
 
 
1566
    JSObjectCallAsFunction(m_context, m_receiverFunction, m_receiver, argc, args.data(), 0);
 
1567
}
 
1568
 
 
1569
bool QtConnectionObject::match(JSContextRef context, QObject* sender, int signalIndex, JSObjectRef receiver, JSObjectRef receiverFunction)
 
1570
{
 
1571
    if (sender != parent() || signalIndex != m_signalIndex)
 
1572
        return false;
 
1573
    JSValueRef* ignoredException = 0;
 
1574
    const bool receiverMatch = (!receiver && !m_receiver) || (receiver && m_receiver && JSValueIsEqual(context, receiver, m_receiver, ignoredException));
 
1575
    return receiverMatch && JSValueIsEqual(context, receiverFunction, m_receiverFunction, ignoredException);
 
1576
}
 
1577
 
 
1578
} }