2
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
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.
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.
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
21
#include "qt_runtime.h"
24
#include "BooleanObject.h"
25
#include "DateInstance.h"
26
#include "DatePrototype.h"
27
#include "FunctionPrototype.h"
28
#include "Interpreter.h"
30
#include "JSContextRefPrivate.h"
31
#include "JSDocument.h"
32
#include "JSDOMBinding.h"
33
#include "JSDOMWindow.h"
34
#include <JSFunction.h>
35
#include "JSGlobalObject.h"
36
#include "JSHTMLElement.h"
39
#include "JSRetainPtr.h"
40
#include "JSUint8ClampedArray.h"
41
#include "ObjectPrototype.h"
42
#include "PropertyNameArray.h"
43
#include "qdatetime.h"
45
#include "qmetaobject.h"
46
#include "qmetatype.h"
48
#include "qstringlist.h"
49
#include "qt_instance.h"
50
#include "qt_pixmapruntime.h"
51
#include "qvarlengtharray.h"
53
#include <wtf/DateMath.h>
56
#include <runtime/Error.h>
57
#include <runtime_array.h>
58
#include <runtime_object.h>
61
Q_DECLARE_METATYPE(QObjectList);
62
Q_DECLARE_METATYPE(QList<int>);
63
Q_DECLARE_METATYPE(QVariant);
65
using namespace WebCore;
71
//#define QTWK_RUNTIME_CONVERSION_DEBUG
72
//#define QTWK_RUNTIME_MATCH_DEBUG
78
inline ~QWKNoDebug(){}
81
inline QWKNoDebug &operator<<(const T &) { return *this; }
84
#ifdef QTWK_RUNTIME_CONVERSION_DEBUG
85
#define qConvDebug() qDebug()
87
#define qConvDebug() QWKNoDebug()
90
#ifdef QTWK_RUNTIME_MATCH_DEBUG
91
#define qMatchDebug() qDebug()
93
#define qMatchDebug() QWKNoDebug()
106
JSUint8ClampedArrayType
109
#if defined(QTWK_RUNTIME_CONVERSION_DEBUG) || defined(QTWK_RUNTIME_MATCH_DEBUG)
110
QDebug operator<<(QDebug dbg, const JSRealType &c)
112
const char *map[] = { "Variant", "Number", "Boolean", "String", "Date",
113
"Array", "RTObject", "Object", "Null"};
115
dbg.nospace() << "JSType(" << ((int)c) << ", " << map[c] << ")";
121
void setException(JSContextRef context, JSValueRef* exception, const QString& text)
126
JSStringRef errorStr = JSStringCreateWithUTF8CString(text.toUtf8());
127
JSValueRef errorVal[] = { JSValueMakeString(context, errorStr) };
128
*exception = JSObjectMakeError(context, 1, errorVal, 0);
129
JSStringRelease(errorStr);
132
struct RuntimeConversion {
133
ConvertToJSValueFunction toJSValueFunc;
134
ConvertToVariantFunction toVariantFunc;
137
typedef QHash<int, RuntimeConversion> RuntimeConversionTable;
138
Q_GLOBAL_STATIC(RuntimeConversionTable, customRuntimeConversions)
140
void registerCustomType(int qtMetaTypeId, ConvertToVariantFunction toVariantFunc, ConvertToJSValueFunction toJSValueFunc)
142
RuntimeConversion conversion;
143
conversion.toJSValueFunc = toJSValueFunc;
144
conversion.toVariantFunc = toVariantFunc;
145
customRuntimeConversions()->insert(qtMetaTypeId, conversion);
148
static bool isJSUint8ClampedArray(JSObjectRef object)
150
return toJS(object)->inherits(&JSUint8ClampedArray::s_info);
153
static bool isJSArray(JSObjectRef object)
155
return toJS(object)->inherits(&JSArray::s_info);
158
static bool isJSDate(JSObjectRef object)
160
return toJS(object)->inherits(&DateInstance::s_info);
163
static bool isQtObject(JSObjectRef object)
165
return toJS(object)->inherits(&RuntimeObject::s_info);
168
static JSRealType valueRealType(JSContextRef context, JSValueRef value, JSValueRef* exception)
170
if (JSValueIsNumber(context, value))
172
if (JSValueIsString(context, value))
174
if (JSValueIsBoolean(context, value))
176
if (JSValueIsNull(context, value))
178
if (!JSValueIsObject(context, value))
179
return String; // I don't know.
181
JSObjectRef object = JSValueToObject(context, value, exception);
183
if (isJSUint8ClampedArray(object))
184
return JSUint8ClampedArrayType;
185
if (isJSArray(object))
187
if (isJSDate(object))
189
if (isQtObject(object))
195
static QString toString(JSStringRef stringRef)
197
return QString(reinterpret_cast<const QChar*>(JSStringGetCharactersPtr(stringRef)), JSStringGetLength(stringRef));
200
static JSValueRef unwrapBoxedPrimitive(JSContextRef context, JSValueRef value, JSObjectRef obj)
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));
213
QVariant convertValueToQVariant(JSContextRef, JSValueRef, QMetaType::Type, int*, HashSet<JSObjectRef>*, int, JSValueRef *exception);
215
static QVariantMap convertValueToQVariantMap(JSContextRef context, JSObjectRef object, HashSet<JSObjectRef>* visitedObjects, int recursionLimit, JSValueRef* exception)
218
JSPropertyNameArrayRef properties = JSObjectCopyPropertyNames(context, object);
219
size_t propertyCount = JSPropertyNameArrayGetCount(properties);
221
for (size_t i = 0; i < propertyCount; ++i) {
222
JSStringRef name = JSPropertyNameArrayGetNameAtIndex(properties, i);
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)
229
else if (propertyConversionDistance >= 0) {
230
result.insert(toString(name), v);
233
JSPropertyNameArrayRelease(properties);
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>()))
242
QList<ItemType> list;
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>();
257
if (list.count() != length)
262
int itemDistance = -1;
263
QVariant variant = convertValueToQVariant(context, value, typeId, &itemDistance, exception);
264
if (itemDistance >= 0) {
265
list << variant.value<ItemType>();
273
static QString toQString(JSContextRef context, JSValueRef value)
275
JSRetainPtr<JSStringRef> string(Adopt, JSValueToStringCopy(context, value, 0));
278
return QString(reinterpret_cast<const QChar*>(JSStringGetCharactersPtr(string.get())), JSStringGetLength(string.get()));
281
static void getGregorianDateTimeUTC(JSContextRef context, JSRealType type, JSValueRef value, JSObjectRef object, JSValueRef* exception, GregorianDateTime* gdt)
283
ExecState* exec = toJS(context);
285
JSObject* jsObject = toJS(object);
286
DateInstance* date = asDateInstance(jsObject);
287
gdt->copyFrom(*date->gregorianDateTimeUTC(exec));
289
double ms = JSValueToNumber(context, value, exception);
290
GregorianDateTime convertedGdt;
291
msToGregorianDateTime(exec, ms, /*utc*/ true, convertedGdt);
292
gdt->copyFrom(convertedGdt);
296
static QDateTime toQDateTimeUTC(JSContextRef context, JSRealType type, JSValueRef value, JSObjectRef object, JSValueRef* exception)
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);
305
QVariant convertValueToQVariant(JSContextRef context, JSValueRef value, QMetaType::Type hint, int *distance, HashSet<JSObjectRef>* visitedObjects, int recursionLimit, JSValueRef* exception)
309
if (!value || !recursionLimit)
312
JSObjectRef object = 0;
313
if (JSValueIsObject(context, value)) {
314
object = JSValueToObject(context, value, 0);
315
if (visitedObjects->contains(object))
318
visitedObjects->add(object);
320
value = unwrapBoxedPrimitive(context, value, object);
323
// check magic pointer values before dereferencing value
324
if (JSValueIsNumber(context, value)
325
&& isnan(JSValueToNumber(context, value, exception))) {
331
if (JSValueIsUndefined(context, value) && hint != QMetaType::QString && hint != (QMetaType::Type) qMetaTypeId<QVariant>()) {
337
JSRealType type = valueRealType(context, value, exception);
338
if (hint == QMetaType::Void) {
341
hint = QMetaType::Double;
344
hint = QMetaType::Bool;
348
hint = QMetaType::QString;
351
hint = QMetaType::QDateTime;
354
hint = QMetaType::QVariantMap;
357
hint = QMetaType::QObjectStar;
359
case JSUint8ClampedArrayType:
360
hint = QMetaType::QByteArray;
363
hint = QMetaType::QVariantList;
368
qConvDebug() << "convertValueToQVariant: jstype is " << type << ", hint is" << hint;
370
if (JSValueIsNull(context, value)
371
&& hint != QMetaType::QObjectStar
372
&& hint != QMetaType::VoidStar
373
&& hint != QMetaType::QString
374
&& hint != (QMetaType::Type) qMetaTypeId<QVariant>()) {
383
case QMetaType::Bool:
384
ret = QVariant(JSValueToBoolean(context, value));
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) {
405
case QMetaType::Double:
408
case QMetaType::Float:
411
case QMetaType::LongLong:
412
case QMetaType::ULongLong:
415
case QMetaType::Long:
416
case QMetaType::ULong:
420
case QMetaType::UInt:
423
case QMetaType::Short:
424
case QMetaType::UShort:
437
case QMetaType::QChar:
438
if (type == Number || type == Boolean) {
439
ret = QVariant(QChar((ushort)JSValueToNumber(context, value, 0)));
445
JSRetainPtr<JSStringRef> str(Adopt, JSValueToStringCopy(context, value, exception));
447
if (str && JSStringGetLength(str.get()) > 0)
448
ch = *reinterpret_cast<const QChar*>(JSStringGetCharactersPtr(str.get()));
457
case QMetaType::QString: {
458
if (JSValueIsNull(context, value) || JSValueIsUndefined(context, value)) {
463
JSRetainPtr<JSStringRef> str(Adopt, JSValueToStringCopy(context, value, exception));
465
QString string(reinterpret_cast<const QChar*>(JSStringGetCharactersPtr(str.get())), JSStringGetLength(str.get()));
466
ret = QVariant(string);
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.
483
case QMetaType::QVariantList:
484
ret = QVariant(convertToList<QVariant>(context, type, object, value, &dist, exception, QMetaType::Void));
487
case QMetaType::QStringList: {
488
ret = QVariant(convertToList<QString>(context, type, object, value, &dist, exception));
492
case QMetaType::QByteArray: {
493
if (type == JSUint8ClampedArrayType) {
494
WTF::Uint8ClampedArray* arr = toUint8ClampedArray(toJS(toJS(context), value));
495
ret = QVariant(QByteArray(reinterpret_cast<const char*>(arr->data()), arr->length()));
498
ret = QVariant(toQString(context, value).toLatin1());
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) {
515
dist = isNumber ? 6 : 0;
516
} else if (hint == QMetaType::QDate) {
518
dist = isNumber ? 8 : 1;
521
dist = isNumber ? 10 : 2;
523
#ifndef QT_NO_DATESTRING
524
} else if (type == String) {
525
QString qstring = toQString(context, value);
527
if (hint == QMetaType::QDateTime) {
528
QDateTime dt = QDateTime::fromString(qstring, Qt::ISODate);
530
dt = QDateTime::fromString(qstring, Qt::TextDate);
532
dt = QDateTime::fromString(qstring, Qt::SystemLocaleDate);
534
dt = QDateTime::fromString(qstring, Qt::LocaleDate);
539
} else if (hint == QMetaType::QDate) {
540
QDate dt = QDate::fromString(qstring, Qt::ISODate);
542
dt = QDate::fromString(qstring, Qt::TextDate);
544
dt = QDate::fromString(qstring, Qt::SystemLocaleDate);
546
dt = QDate::fromString(qstring, Qt::LocaleDate);
552
QTime dt = QTime::fromString(qstring, Qt::ISODate);
554
dt = QTime::fromString(qstring, Qt::TextDate);
556
dt = QTime::fromString(qstring, Qt::SystemLocaleDate);
558
dt = QTime::fromString(qstring, Qt::LocaleDate);
564
#endif // QT_NO_DATESTRING
568
case QMetaType::QObjectStar:
570
QtInstance* qtinst = QtInstance::getInstance(toJS(object));
572
if (qtinst->getObject()) {
573
qConvDebug() << "found instance, with object:" << (void*) qtinst->getObject();
574
ret = QVariant::fromValue(qtinst->getObject());
578
qConvDebug() << "can't convert deleted qobject";
581
qConvDebug() << "wasn't a qtinstance";
583
} else if (type == Null) {
584
QObject* nullobj = 0;
585
ret = QVariant::fromValue(nullobj);
588
qConvDebug() << "previous type was not an object:" << type;
592
case QMetaType::VoidStar:
594
QtInstance* qtinst = QtInstance::getInstance(toJS(object));
596
if (qtinst->getObject()) {
597
qConvDebug() << "found instance, with object:" << (void*) qtinst->getObject();
598
ret = QVariant::fromValue((void *)qtinst->getObject());
602
qConvDebug() << "can't convert deleted qobject";
605
qConvDebug() << "wasn't a qtinstance";
607
} else if (type == Null) {
608
ret = QVariant::fromValue((void*)0);
610
} else if (type == Number) {
611
// I don't think that converting a double to a pointer is a wise
612
// move. Except maybe 0.
613
qConvDebug() << "got number for void * - not converting, seems unsafe:" << JSValueToNumber(context, value, 0);
615
qConvDebug() << "void* - unhandled type" << type;
620
// Non const type ids
621
if (hint == (QMetaType::Type) qMetaTypeId<QObjectList>())
623
ret = QVariant::fromValue(convertToList<QObject*>(context, type, object, value, &dist, exception));
625
} else if (hint == (QMetaType::Type) qMetaTypeId<QList<int> >()) {
626
ret = QVariant::fromValue(convertToList<int>(context, type, object, value, &dist, exception));
629
if (QtPixmapRuntime::canHandle(static_cast<QMetaType::Type>(hint))) {
630
ret = QtPixmapRuntime::toQt(context, object, static_cast<QMetaType::Type>(hint), exception);
631
} else if (customRuntimeConversions()->contains(hint)) {
632
ret = customRuntimeConversions()->value(hint).toVariantFunc(toJS(object), &dist, visitedObjects);
635
} else if (hint == (QMetaType::Type) qMetaTypeId<QVariant>()) {
636
if (JSValueIsNull(context, value) || JSValueIsUndefined(context, value)) {
641
if (type == Object) {
642
// Since we haven't really visited this object yet, we remove it
643
visitedObjects->remove(object);
646
// And then recurse with the autodetect flag
647
ret = convertValueToQVariant(context, value, QMetaType::Void, distance, visitedObjects, recursionLimit, exception);
664
QVariant convertValueToQVariant(JSContextRef context, JSValueRef value, QMetaType::Type hint, int *distance, JSValueRef *exception)
666
const int recursionLimit = 200;
667
HashSet<JSObjectRef> visitedObjects;
668
return convertValueToQVariant(context, value, hint, distance, &visitedObjects, recursionLimit, exception);
671
JSValueRef convertQVariantToValue(JSContextRef context, PassRefPtr<RootObject> root, const QVariant& variant, JSValueRef *exception)
673
// Variants with QObject * can be isNull but not a null pointer
674
// An empty QString variant is also null
675
QMetaType::Type type = (QMetaType::Type) variant.userType();
677
qConvDebug() << "convertQVariantToValue: metatype:" << type << ", isnull: " << variant.isNull();
678
if (variant.isNull() &&
679
type != QMetaType::QObjectStar &&
680
type != QMetaType::VoidStar &&
681
type != QMetaType::QWidgetStar &&
682
type != QMetaType::QString) {
683
return JSValueMakeNull(context);
686
if (type == QMetaType::Bool)
687
return JSValueMakeBoolean(context, variant.toBool());
689
if (type == QMetaType::Int ||
690
type == QMetaType::UInt ||
691
type == QMetaType::Long ||
692
type == QMetaType::ULong ||
693
type == QMetaType::LongLong ||
694
type == QMetaType::ULongLong ||
695
type == QMetaType::Short ||
696
type == QMetaType::UShort ||
697
type == QMetaType::Float ||
698
type == QMetaType::Double)
699
return JSValueMakeNumber(context, variant.toDouble());
701
if (type == QMetaType::QDateTime ||
702
type == QMetaType::QDate ||
703
type == QMetaType::QTime) {
705
QDate date = QDate::currentDate();
706
QTime time(0,0,0); // midnight
708
if (type == QMetaType::QDate)
709
date = variant.value<QDate>();
710
else if (type == QMetaType::QTime)
711
time = variant.value<QTime>();
713
QDateTime dt = variant.value<QDateTime>().toLocalTime();
718
// Dates specified this way are in local time (we convert DateTimes above)
719
const JSValueRef arguments[] = {
720
JSValueMakeNumber(context, date.year()),
721
JSValueMakeNumber(context, date.month() - 1),
722
JSValueMakeNumber(context, date.day()),
723
JSValueMakeNumber(context, time.hour()),
724
JSValueMakeNumber(context, time.minute()),
725
JSValueMakeNumber(context, time.second()),
726
JSValueMakeNumber(context, time.msec())
728
return JSObjectMakeDate(context, 7, arguments, exception);
731
if (type == QMetaType::QByteArray) {
732
QByteArray qtByteArray = variant.value<QByteArray>();
733
WTF::RefPtr<WTF::Uint8ClampedArray> wtfByteArray = WTF::Uint8ClampedArray::createUninitialized(qtByteArray.length());
734
memcpy(wtfByteArray->data(), qtByteArray.constData(), qtByteArray.length());
735
ExecState* exec = toJS(context);
736
return toRef(exec, toJS(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), wtfByteArray.get()));
739
if (type == QMetaType::QObjectStar || type == QMetaType::QWidgetStar) {
740
QObject* obj = variant.value<QObject*>();
742
return JSValueMakeNull(context);
743
ExecState* exec = toJS(context);
744
return toRef(exec, QtInstance::getQtInstance(obj, root, QtInstance::QtOwnership)->createRuntimeObject(exec));
747
if (QtPixmapRuntime::canHandle(static_cast<QMetaType::Type>(variant.type())))
748
return QtPixmapRuntime::toJS(context, variant, exception);
750
if (customRuntimeConversions()->contains(type)) {
751
if (!root->globalObject()->inherits(&JSDOMWindow::s_info))
752
return JSValueMakeUndefined(context);
754
Document* document = (static_cast<JSDOMWindow*>(root->globalObject()))->impl()->document();
756
return JSValueMakeUndefined(context);
757
ExecState* exec = toJS(context);
758
return toRef(exec, customRuntimeConversions()->value(type).toJSValueFunc(exec, toJSDOMGlobalObject(document, exec), variant));
761
if (type == QMetaType::QVariantMap) {
762
// create a new object, and stuff properties into it
763
JSObjectRef ret = JSObjectMake(context, 0, 0);
764
QVariantMap map = variant.value<QVariantMap>();
765
QVariantMap::const_iterator i = map.constBegin();
766
while (i != map.constEnd()) {
768
JSStringRef propertyName = JSStringCreateWithCharacters(reinterpret_cast<const JSChar*>(s.constData()), s.length());
769
JSValueRef propertyValue = convertQVariantToValue(context, root.get(), i.value(), /*ignored exception*/0);
771
JSObjectSetProperty(context, ret, propertyName, propertyValue, kJSPropertyAttributeNone, /*ignored exception*/0);
772
JSStringRelease(propertyName);
780
if (type == QMetaType::QVariantList) {
781
// ### TODO: Could use special array class that lazily converts.
782
// See https://bugs.webkit.org/show_bug.cgi?id=94691
783
QVariantList vl = variant.toList();
784
JSObjectRef array = JSObjectMakeArray(context, 0, 0, exception);
785
if (exception && *exception)
787
for (int i = 0; i < vl.count(); ++i) {
788
JSValueRef property = convertQVariantToValue(context, root.get(), vl.at(i), /*ignored exception*/0);
790
JSObjectSetPropertyAtIndex(context, array, i, property, /*ignored exception*/0);
793
} else if (type == QMetaType::QStringList) {
794
QStringList sl = variant.value<QStringList>();
795
JSObjectRef array = JSObjectMakeArray(context, 0, 0, exception);
796
for (int i = 0; i < sl.count(); ++i) {
797
const QString& s = sl.at(i);
798
JSStringRef jsString = JSStringCreateWithCharacters(reinterpret_cast<const JSChar*>(s.constData()), s.length());
799
JSObjectSetPropertyAtIndex(context, array, i, JSValueMakeString(context, jsString), /*ignored exception*/0);
800
JSStringRelease(jsString);
803
} else if (type == static_cast<QMetaType::Type>(qMetaTypeId<QObjectList>())) {
804
QObjectList ol = variant.value<QObjectList>();
805
JSObjectRef array = JSObjectMakeArray(context, 0, 0, exception);
806
ExecState* exec = toJS(context);
807
for (int i = 0; i < ol.count(); ++i) {
808
JSValueRef jsObject = toRef(exec, QtInstance::getQtInstance(ol.at(i), root, QtInstance::QtOwnership)->createRuntimeObject(exec));
809
JSObjectSetPropertyAtIndex(context, array, i, jsObject, /*ignored exception*/0);
812
} else if (type == static_cast<QMetaType::Type>(qMetaTypeId<QList<int> >())) {
813
QList<int> il = variant.value<QList<int> >();
814
JSObjectRef array = JSObjectMakeArray(context, 0, 0, exception);
815
for (int i = 0; i < il.count(); ++i)
816
JSObjectSetPropertyAtIndex(context, array, i, JSValueMakeNumber(context, il.at(i)), /*ignored exception*/0);
820
if (type == (QMetaType::Type)qMetaTypeId<QVariant>()) {
821
QVariant real = variant.value<QVariant>();
822
qConvDebug() << "real variant is:" << real;
823
return convertQVariantToValue(context, root.get(), real, exception);
826
qConvDebug() << "fallback path for" << variant << variant.userType();
828
QString string = variant.toString();
829
JSStringRef jsstring = JSStringCreateWithCharacters(reinterpret_cast<const JSChar*>(string.constData()), string.length());
830
JSValueRef value = JSValueMakeString(context, jsstring);
831
JSStringRelease(jsstring);
835
// Type conversion metadata (from QtScript originally)
836
class QtMethodMatchType
849
: m_kind(Invalid) { }
854
QMetaType::Type typeId() const;
857
{ return (m_kind != Invalid); }
859
bool isVariant() const
860
{ return (m_kind == Variant); }
862
bool isMetaType() const
863
{ return (m_kind == MetaType); }
865
bool isUnresolved() const
866
{ return (m_kind == Unresolved); }
868
bool isMetaEnum() const
869
{ return (m_kind == MetaEnum); }
871
QByteArray name() const;
873
int enumeratorIndex() const
874
{ Q_ASSERT(isMetaEnum()); return m_typeId; }
876
static QtMethodMatchType variant()
877
{ return QtMethodMatchType(Variant); }
879
static QtMethodMatchType metaType(int typeId, const QByteArray &name)
880
{ return QtMethodMatchType(MetaType, typeId, name); }
882
static QtMethodMatchType metaEnum(int enumIndex, const QByteArray &name)
883
{ return QtMethodMatchType(MetaEnum, enumIndex, name); }
885
static QtMethodMatchType unresolved(const QByteArray &name)
886
{ return QtMethodMatchType(Unresolved, /*typeId=*/0, name); }
889
QtMethodMatchType(Kind kind, int typeId = 0, const QByteArray &name = QByteArray())
890
: m_kind(kind), m_typeId(typeId), m_name(name) { }
897
QMetaType::Type QtMethodMatchType::typeId() const
900
return (QMetaType::Type) QMetaType::type("QVariant");
901
return (QMetaType::Type) (isMetaEnum() ? QMetaType::Int : m_typeId);
904
QByteArray QtMethodMatchType::name() const
906
if (!m_name.isEmpty())
908
else if (m_kind == Variant)
913
struct QtMethodMatchData
917
QVector<QtMethodMatchType> types;
918
QVarLengthArray<QVariant, 10> args;
920
QtMethodMatchData(int dist, int idx, QVector<QtMethodMatchType> typs,
921
const QVarLengthArray<QVariant, 10> &as)
922
: matchDistance(dist), index(idx), types(typs), args(as) { }
927
{ return (index != -1); }
929
int firstUnresolvedIndex() const
931
for (int i=0; i < types.count(); i++) {
932
if (types.at(i).isUnresolved())
939
static int indexOfMetaEnum(const QMetaObject *meta, const QByteArray &str)
943
int scopeIdx = str.indexOf("::");
944
if (scopeIdx != -1) {
945
scope = str.left(scopeIdx);
946
name = str.mid(scopeIdx + 2);
950
for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
951
QMetaEnum m = meta->enumerator(i);
952
if ((m.name() == name)/* && (scope.isEmpty() || (m.scope() == scope))*/)
958
// Helper function for resolving methods
959
// Largely based on code in QtScript for compatibility reasons
960
static int findMethodIndex(JSContextRef context,
961
const QMetaObject* meta,
962
const QByteArray& signature,
964
const JSValueRef arguments[],
966
QVarLengthArray<QVariant, 10> &vars,
968
JSValueRef* exception)
970
QList<int> matchingIndices;
972
bool overloads = !signature.contains('(');
974
int count = meta->methodCount();
975
for (int i = count - 1; i >= 0; --i) {
976
const QMetaMethod m = meta->method(i);
978
// Don't choose private methods
979
if (m.access() == QMetaMethod::Private && !allowPrivate)
982
// try and find all matching named methods
983
if (m.signature() == signature)
984
matchingIndices.append(i);
985
else if (overloads) {
986
QByteArray rawsignature = m.signature();
987
rawsignature.truncate(rawsignature.indexOf('('));
988
if (rawsignature == signature)
989
matchingIndices.append(i);
993
int chosenIndex = -1;
994
QVector<QtMethodMatchType> chosenTypes;
996
QVarLengthArray<QVariant, 10> args;
997
QVector<QtMethodMatchData> candidates;
998
QVector<QtMethodMatchData> unresolved;
999
QVector<int> tooFewArgs;
1000
QVector<int> conversionFailed;
1002
foreach(int index, matchingIndices) {
1003
QMetaMethod method = meta->method(index);
1005
QVector<QtMethodMatchType> types;
1006
bool unresolvedTypes = false;
1008
// resolve return type
1009
QByteArray returnTypeName = method.typeName();
1010
int rtype = QMetaType::type(returnTypeName);
1011
if ((rtype == 0) && !returnTypeName.isEmpty()) {
1012
if (returnTypeName == "QVariant") {
1013
types.append(QtMethodMatchType::variant());
1014
} else if (returnTypeName.endsWith('*')) {
1015
types.append(QtMethodMatchType::metaType(QMetaType::VoidStar, returnTypeName));
1017
int enumIndex = indexOfMetaEnum(meta, returnTypeName);
1018
if (enumIndex != -1)
1019
types.append(QtMethodMatchType::metaEnum(enumIndex, returnTypeName));
1021
unresolvedTypes = true;
1022
types.append(QtMethodMatchType::unresolved(returnTypeName));
1026
if (returnTypeName == "QVariant")
1027
types.append(QtMethodMatchType::variant());
1029
types.append(QtMethodMatchType::metaType(rtype, returnTypeName));
1032
// resolve argument types
1033
QList<QByteArray> parameterTypeNames = method.parameterTypes();
1034
for (int i = 0; i < parameterTypeNames.count(); ++i) {
1035
QByteArray argTypeName = parameterTypeNames.at(i);
1036
int atype = QMetaType::type(argTypeName);
1038
if (argTypeName == "QVariant") {
1039
types.append(QtMethodMatchType::variant());
1041
int enumIndex = indexOfMetaEnum(meta, argTypeName);
1042
if (enumIndex != -1)
1043
types.append(QtMethodMatchType::metaEnum(enumIndex, argTypeName));
1045
unresolvedTypes = true;
1046
types.append(QtMethodMatchType::unresolved(argTypeName));
1050
if (argTypeName == "QVariant")
1051
types.append(QtMethodMatchType::variant());
1053
types.append(QtMethodMatchType::metaType(atype, argTypeName));
1057
// If the native method requires more arguments than what was passed from JavaScript
1058
if (argumentCount + 1 < static_cast<unsigned>(types.count())) {
1059
qMatchDebug() << "Match:too few args for" << method.signature();
1060
tooFewArgs.append(index);
1064
if (unresolvedTypes) {
1065
qMatchDebug() << "Match:unresolved arg types for" << method.signature();
1066
// remember it so we can give an error message later, if necessary
1067
unresolved.append(QtMethodMatchData(/*matchDistance=*/INT_MAX, index,
1068
types, QVarLengthArray<QVariant, 10>()));
1072
// Now convert arguments
1073
if (args.count() != types.count())
1074
args.resize(types.count());
1076
QtMethodMatchType retType = types[0];
1077
args[0] = QVariant(retType.typeId(), (void *)0); // the return value
1079
bool converted = true;
1080
int matchDistance = 0;
1081
for (unsigned i = 0; converted && i + 1 < static_cast<unsigned>(types.count()); ++i) {
1082
JSValueRef arg = i < argumentCount ? arguments[i] : JSValueMakeUndefined(context);
1084
int argdistance = -1;
1085
QVariant v = convertValueToQVariant(context, arg, types.at(i+1).typeId(), &argdistance, exception);
1086
if (argdistance >= 0) {
1087
matchDistance += argdistance;
1090
qMatchDebug() << "failed to convert argument " << i << "type" << types.at(i+1).typeId() << QMetaType::typeName(types.at(i+1).typeId());
1095
qMatchDebug() << "Match: " << method.signature() << (converted ? "converted":"failed to convert") << "distance " << matchDistance;
1098
if ((argumentCount + 1 == static_cast<unsigned>(types.count()))
1099
&& (matchDistance == 0)) {
1100
// perfect match, use this one
1101
chosenIndex = index;
1104
QtMethodMatchData currentMatch(matchDistance, index, types, args);
1105
if (candidates.isEmpty())
1106
candidates.append(currentMatch);
1108
QtMethodMatchData bestMatchSoFar = candidates.at(0);
1109
if ((args.count() > bestMatchSoFar.args.count())
1110
|| ((args.count() == bestMatchSoFar.args.count())
1111
&& (matchDistance <= bestMatchSoFar.matchDistance)))
1112
candidates.prepend(currentMatch);
1114
candidates.append(currentMatch);
1117
conversionFailed.append(index);
1124
if (chosenIndex == -1 && candidates.count() == 0) {
1125
// No valid functions at all - format an error message
1126
if (!conversionFailed.isEmpty()) {
1127
QString message = QString::fromLatin1("incompatible type of argument(s) in call to %0(); candidates were\n")
1128
.arg(QLatin1String(signature));
1129
for (int i = 0; i < conversionFailed.size(); ++i) {
1131
message += QLatin1String("\n");
1132
QMetaMethod mtd = meta->method(conversionFailed.at(i));
1133
message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
1135
setException(context, exception, message);
1136
} else if (!unresolved.isEmpty()) {
1137
QtMethodMatchData argsInstance = unresolved.first();
1138
int unresolvedIndex = argsInstance.firstUnresolvedIndex();
1139
Q_ASSERT(unresolvedIndex != -1);
1140
QtMethodMatchType unresolvedType = argsInstance.types.at(unresolvedIndex);
1141
QString message = QString::fromLatin1("cannot call %0(): unknown type `%1'")
1142
.arg(QString::fromLatin1(signature))
1143
.arg(QLatin1String(unresolvedType.name()));
1144
setException(context, exception, message);
1146
QString message = QString::fromLatin1("too few arguments in call to %0(); candidates are\n")
1147
.arg(QLatin1String(signature));
1148
for (int i = 0; i < tooFewArgs.size(); ++i) {
1150
message += QLatin1String("\n");
1151
QMetaMethod mtd = meta->method(tooFewArgs.at(i));
1152
message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
1154
setException(context, exception, message);
1158
if (chosenIndex == -1 && candidates.count() > 0) {
1159
QtMethodMatchData bestMatch = candidates.at(0);
1160
if ((candidates.size() > 1)
1161
&& (bestMatch.args.count() == candidates.at(1).args.count())
1162
&& (bestMatch.matchDistance == candidates.at(1).matchDistance)) {
1164
QString message = QString::fromLatin1("ambiguous call of overloaded function %0(); candidates were\n")
1165
.arg(QLatin1String(signature));
1166
for (int i = 0; i < candidates.size(); ++i) {
1167
// Only candidate for overload if argument count and match distance is same as best match
1168
if (candidates.at(i).args.count() == bestMatch.args.count()
1169
|| candidates.at(i).matchDistance == bestMatch.matchDistance) {
1171
message += QLatin1String("\n");
1172
QMetaMethod mtd = meta->method(candidates.at(i).index);
1173
message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
1176
setException(context, exception, message);
1178
chosenIndex = bestMatch.index;
1179
args = bestMatch.args;
1183
if (chosenIndex != -1) {
1184
/* Copy the stuff over */
1186
vars.resize(args.count());
1187
for (i=0; i < args.count(); i++) {
1189
vvars[i] = vars[i].data();
1196
// Signals are not fuzzy matched as much as methods
1197
static int findSignalIndex(const QMetaObject* meta, int initialIndex, QByteArray signature)
1199
int index = initialIndex;
1200
QMetaMethod method = meta->method(index);
1201
bool overloads = !signature.contains('(');
1202
if (overloads && (method.attributes() & QMetaMethod::Cloned)) {
1203
// find the most general method
1205
method = meta->method(--index);
1206
} while (method.attributes() & QMetaMethod::Cloned);
1211
static JSClassRef prototypeForSignalsAndSlots()
1213
static JSClassDefinition classDef = {
1214
0, kJSClassAttributeNoAutomaticPrototype, 0, 0, 0, 0,
1215
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1217
static JSClassRef cls = JSClassCreate(&classDef);
1221
QtRuntimeMethod::QtRuntimeMethod(JSContextRef ctx, QObject* object, const QByteArray& identifier, int index, int flags, QtInstance* instance)
1223
, m_identifier(identifier)
1226
, m_instance(instance)
1230
QtRuntimeMethod::~QtRuntimeMethod()
1234
JSValueRef QtRuntimeMethod::call(JSContextRef context, JSObjectRef function, JSObjectRef /*thisObject*/, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
1236
QtRuntimeMethod* d = toRuntimeMethod(context, function);
1238
setException(context, exception, QLatin1String("cannot call function of deleted runtime method"));
1239
return JSValueMakeUndefined(context);
1241
QObject* obj = d->m_object;
1244
setException(context, exception, QLatin1String("cannot call function of deleted QObject"));
1245
return JSValueMakeUndefined(context);
1248
// Allow for maximum of 10 arguments and size stack arrays accordingly.
1249
if (argumentCount > 10)
1250
return JSValueMakeUndefined(context);
1252
QVarLengthArray<QVariant, 10> vargs;
1255
int methodIndex = findMethodIndex(context, obj->metaObject(), d->m_identifier, argumentCount, arguments,
1256
(d->m_flags & AllowPrivate), vargs, (void **)qargs, exception);
1258
if (QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, methodIndex, qargs) >= 0)
1259
return JSValueMakeUndefined(context);
1261
if (vargs.size() > 0 && vargs[0].isValid())
1262
return convertQVariantToValue(context, d->m_instance->rootObject(), vargs[0], exception);
1264
return JSValueMakeUndefined(context);
1267
JSValueRef QtRuntimeMethod::connect(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
1269
return connectOrDisconnect(context, function, thisObject, argumentCount, arguments, exception, true);
1272
JSValueRef QtRuntimeMethod::disconnect(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
1274
return connectOrDisconnect(context, function, thisObject, argumentCount, arguments, exception, false);
1277
JSObjectRef QtRuntimeMethod::jsObjectRef(JSContextRef context, JSValueRef* exception)
1280
return toRef(m_jsObject.get());
1282
static JSStringRef connectStr = JSStringCreateWithUTF8CString("connect");
1283
static JSStringRef disconnectStr = JSStringCreateWithUTF8CString("disconnect");
1284
JSRetainPtr<JSStringRef> actualNameStr(Adopt, JSStringCreateWithUTF8CString(m_identifier.constData()));
1286
JSObjectRef object = JSObjectMakeFunctionWithCallback(context, actualNameStr.get(), call);
1288
JSObjectRef generalFunctionProto = JSValueToObject(context, JSObjectGetPrototype(context, object), 0);
1289
JSObjectRef runtimeMethodProto = JSObjectMake(context, prototypeForSignalsAndSlots(), this);
1290
JSObjectSetPrototype(context, runtimeMethodProto, generalFunctionProto);
1292
JSObjectSetPrototype(context, object, runtimeMethodProto);
1294
JSObjectRef connectFunction = JSObjectMakeFunctionWithCallback(context, connectStr, connect);
1295
JSObjectSetPrototype(context, connectFunction, runtimeMethodProto);
1297
JSObjectRef disconnectFunction = JSObjectMakeFunctionWithCallback(context, disconnectStr, disconnect);
1298
JSObjectSetPrototype(context, disconnectFunction, runtimeMethodProto);
1300
const JSPropertyAttributes attributes = kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete;
1301
JSObjectSetProperty(context, object, connectStr, connectFunction, attributes, exception);
1302
JSObjectSetProperty(context, object, disconnectStr, disconnectFunction, attributes, exception);
1304
m_jsObject = PassWeak<JSObject>(toJS(object));
1309
QtRuntimeMethod* QtRuntimeMethod::toRuntimeMethod(JSContextRef context, JSObjectRef object)
1311
JSObjectRef proto = JSValueToObject(context, JSObjectGetPrototype(context, object), 0);
1314
if (!JSValueIsObjectOfClass(context, proto, prototypeForSignalsAndSlots()))
1316
return static_cast<QtRuntimeMethod*>(JSObjectGetPrivate(proto));
1320
JSValueRef QtRuntimeMethod::connectOrDisconnect(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception, bool connect)
1322
QtRuntimeMethod* d = toRuntimeMethod(context, thisObject);
1324
d = toRuntimeMethod(context, function);
1326
QString errorStr = QString::fromLatin1("QtMetaMethod.%1: Cannot connect to/from deleted QObject").arg(connect ? QLatin1String("connect") : QLatin1String("disconnect"));
1327
setException(context, exception, errorStr);
1328
return JSValueMakeUndefined(context);
1331
QString functionName = connect ? QLatin1String("connect") : QLatin1String("disconnect");
1333
if (!argumentCount) {
1334
QString errorStr = QString::fromLatin1("QtMetaMethod.%1: no arguments given").arg(connect ? QLatin1String("connect") : QLatin1String("disconnect"));
1335
setException(context, exception, errorStr);
1336
return JSValueMakeUndefined(context);
1339
if ((!(d->m_flags & QtRuntimeMethod::MethodIsSignal))) {
1340
setException(context, exception, QString::fromLatin1("QtMetaMethod.%3: %1::%2() is not a signal").arg(QString::fromUtf8(d->m_object.data()->metaObject()->className())).arg(QString::fromAscii(d->m_identifier)).arg(functionName));
1341
return JSValueMakeUndefined(context);
1344
QObject* sender = d->m_object.data();
1347
setException(context, exception, QLatin1String("cannot call function of deleted QObject"));
1348
return JSValueMakeUndefined(context);
1351
int signalIndex = findSignalIndex(sender->metaObject(), d->m_index, d->m_identifier);
1353
JSObjectRef targetObject = 0;
1354
JSObjectRef targetFunction = 0;
1356
if (argumentCount == 1) {
1357
if (!JSValueIsObject(context, arguments[0])) {
1358
setException(context, exception, QString::fromLatin1("QtMetaMethod.%1: target is not a function").arg(functionName));
1359
return JSValueMakeUndefined(context);
1361
targetFunction = JSValueToObject(context, arguments[0], exception);
1363
// object.signal.connect(someFunction);
1364
if (JSObjectIsFunction(context, targetFunction)) {
1365
if (QtRuntimeMethod* targetMethod = toRuntimeMethod(context, targetFunction))
1366
targetObject = toRef(QtInstance::getQtInstance(targetMethod->m_object.data(), d->m_instance->rootObject(), QtInstance::QtOwnership)->createRuntimeObject(toJS(context)));
1370
// object.signal.connect(object, someFunction);
1371
targetObject = JSValueToObject(context, arguments[0], exception);
1372
if (JSValueIsObject(context, arguments[1])) {
1373
JSObjectRef obj = JSValueToObject(context, arguments[1], exception);
1374
if (JSObjectIsFunction(context, obj))
1375
targetFunction = obj;
1377
if (!targetFunction) {
1378
// Maybe the second argument is a string
1379
JSValueRef conversionException = 0;
1380
JSRetainPtr<JSStringRef> functionName(Adopt, JSValueToStringCopy(context, arguments[1], &conversionException));
1381
if (functionName && !conversionException) {
1382
JSValueRef functionProperty = JSObjectGetProperty(context, targetObject, functionName.get(), &conversionException);
1383
if (!conversionException && functionProperty && JSValueIsObject(context, functionProperty)) {
1384
targetFunction = JSValueToObject(context, functionProperty, 0);
1385
if (!JSObjectIsFunction(context, targetFunction))
1392
// object.signal.connect(someObject);
1393
if (!targetFunction) {
1394
QString message = QLatin1String("QtMetaMethod.%1: target is not a function");
1396
message = message.arg(QLatin1String("connect"));
1398
message = message.arg(QLatin1String("disconnect"));
1399
setException(context, exception, message);
1400
return JSValueMakeUndefined(context);
1404
// to connect, we need:
1405
// target object [from ctor]
1406
// target signal index etc. [from ctor]
1407
// receiver function [from arguments]
1408
// receiver this object [from arguments]
1410
QtConnectionObject* conn = new QtConnectionObject(context, QtInstance::getQtInstance(sender, d->m_instance->rootObject(), QtInstance::QtOwnership), signalIndex, targetObject, targetFunction);
1411
bool ok = QMetaObject::connect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
1414
QString msg = QString(QLatin1String("QtMetaMethod.connect: failed to connect to %1::%2()"))
1415
.arg(QLatin1String(sender->metaObject()->className()))
1416
.arg(QLatin1String(d->m_identifier));
1417
setException(context, exception, msg);
1418
return JSValueMakeUndefined(context);
1422
QtConnectionObject::connections.insert(sender, conn);
1424
return JSValueMakeUndefined(context);
1427
// Now to find our previous connection object.
1428
QList<QtConnectionObject*> conns = QtConnectionObject::connections.values(sender);
1430
foreach (QtConnectionObject* conn, conns) {
1431
// Is this the right connection?
1432
if (!conn->match(context, sender, signalIndex, targetObject, targetFunction))
1435
// Yep, disconnect it
1436
QMetaObject::disconnect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
1437
delete conn; // this will also remove it from the map
1438
return JSValueMakeUndefined(context);
1441
QString msg = QString::fromLatin1("QtMetaMethod.disconnect: failed to disconnect from %1::%2()")
1442
.arg(QLatin1String(sender->metaObject()->className()))
1443
.arg(QLatin1String(d->m_identifier));
1445
setException(context, exception, msg);
1446
return JSValueMakeUndefined(context);
1451
QMultiMap<QObject*, QtConnectionObject*> QtConnectionObject::connections;
1453
QtConnectionObject::QtConnectionObject(JSContextRef context, PassRefPtr<QtInstance> senderInstance, int signalIndex, JSObjectRef receiver, JSObjectRef receiverFunction)
1454
: QObject(senderInstance->getObject())
1455
, m_context(JSContextGetGlobalContext(context))
1456
, m_rootObject(senderInstance->rootObject())
1457
, m_signalIndex(signalIndex)
1458
, m_receiver(receiver)
1459
, m_receiverFunction(receiverFunction)
1462
JSValueProtect(m_context, m_receiver);
1463
JSValueProtect(m_context, m_receiverFunction);
1466
QtConnectionObject::~QtConnectionObject()
1468
connections.remove(parent(), this);
1471
JSValueUnprotect(m_context, m_receiver);
1472
JSValueUnprotect(m_context, m_receiverFunction);
1475
static const uint qt_meta_data_QtConnectionObject[] = {
1485
// slots: signature, parameters, type, tag, flags
1486
28, 27, 27, 27, 0x0a,
1491
static const char qt_meta_stringdata_QtConnectionObject[] = {
1492
"JSC::Bindings::QtConnectionObject\0\0execute()\0"
1495
const QMetaObject QtConnectionObject::staticMetaObject = {
1496
{ &QObject::staticMetaObject, qt_meta_stringdata_QtConnectionObject,
1497
qt_meta_data_QtConnectionObject, 0 }
1500
const QMetaObject *QtConnectionObject::metaObject() const
1502
return &staticMetaObject;
1505
void *QtConnectionObject::qt_metacast(const char *_clname)
1507
if (!_clname) return 0;
1508
if (!strcmp(_clname, qt_meta_stringdata_QtConnectionObject))
1509
return static_cast<void*>(const_cast<QtConnectionObject*>(this));
1510
return QObject::qt_metacast(_clname);
1513
// This is what moc would generate except by the fact that we pass all arguments to our execute() slot.
1514
int QtConnectionObject::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
1516
_id = QObject::qt_metacall(_c, _id, _a);
1519
if (_c == QMetaObject::InvokeMetaMethod) {
1521
case 0: execute(_a); break;
1528
void QtConnectionObject::execute(void** argv)
1530
QObject* sender = parent();
1531
const QMetaObject* meta = sender->metaObject();
1532
const QMetaMethod method = meta->method(m_signalIndex);
1534
QList<QByteArray> parameterTypes = method.parameterTypes();
1536
JSValueRef* ignoredException = 0;
1537
JSRetainPtr<JSStringRef> lengthProperty(JSStringCreateWithUTF8CString("length"));
1538
int receiverLength = int(JSValueToNumber(m_context, JSObjectGetProperty(m_context, m_receiverFunction, lengthProperty.get(), ignoredException), ignoredException));
1539
int argc = qMax(parameterTypes.count(), receiverLength);
1540
WTF::Vector<JSValueRef> args(argc);
1542
for (int i = 0; i < argc; i++) {
1543
int argType = QMetaType::type(parameterTypes.at(i));
1544
args[i] = convertQVariantToValue(m_context, m_rootObject, QVariant(argType, argv[i+1]), ignoredException);
1547
JSObjectCallAsFunction(m_context, m_receiverFunction, m_receiver, argc, args.data(), 0);
1550
bool QtConnectionObject::match(JSContextRef context, QObject* sender, int signalIndex, JSObjectRef receiver, JSObjectRef receiverFunction)
1552
if (sender != parent() || signalIndex != m_signalIndex)
1554
JSValueRef* ignoredException = 0;
1555
const bool receiverMatch = (!receiver && !m_receiver) || (receiver && m_receiver && JSValueIsEqual(context, receiver, m_receiver, ignoredException));
1556
return receiverMatch && JSValueIsEqual(context, receiverFunction, m_receiverFunction, ignoredException);