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 "JSDocument.h"
31 #include "JSDOMBinding.h"
32 #include "JSDOMWindow.h"
33 #include <JSFunction.h>
34 #include "JSGlobalObject.h"
35 #include "JSHTMLElement.h"
38 #include "JSRetainPtr.h"
39 #include "JSUint8ClampedArray.h"
40 #include "ObjectPrototype.h"
41 #include "PropertyNameArray.h"
42 #include "RegExpConstructor.h"
43 #include "RegExpObject.h"
44 #include "qdatetime.h"
46 #include "qmetaobject.h"
47 #include "qmetatype.h"
49 #include "qstringlist.h"
50 #include "qt_instance.h"
51 #include "qt_pixmapruntime.h"
52 #include "qvarlengtharray.h"
54 #include <wtf/DateMath.h>
57 #include <runtime/Error.h>
58 #include <runtime_array.h>
59 #include <runtime_object.h>
62 Q_DECLARE_METATYPE(QObjectList);
63 Q_DECLARE_METATYPE(QList<int>);
64 Q_DECLARE_METATYPE(QVariant);
66 using namespace WebCore;
72 //#define QTWK_RUNTIME_CONVERSION_DEBUG
73 //#define QTWK_RUNTIME_MATCH_DEBUG
79 inline ~QWKNoDebug(){}
82 inline QWKNoDebug &operator<<(const T &) { return *this; }
85 #ifdef QTWK_RUNTIME_CONVERSION_DEBUG
86 #define qConvDebug() qDebug()
88 #define qConvDebug() QWKNoDebug()
91 #ifdef QTWK_RUNTIME_MATCH_DEBUG
92 #define qMatchDebug() qDebug()
94 #define qMatchDebug() QWKNoDebug()
112 #if defined(QTWK_RUNTIME_CONVERSION_DEBUG) || defined(QTWK_RUNTIME_MATCH_DEBUG)
113 QDebug operator<<(QDebug dbg, const JSRealType &c)
115 const char *map[] = { "Variant", "Number", "Boolean", "String", "Date",
116 "RegExp", "Array", "RTObject", "Object", "Null", "RTArray"};
118 dbg.nospace() << "JSType(" << ((int)c) << ", " << map[c] << ")";
124 struct RuntimeConversion {
125 ConvertToJSValueFunction toJSValueFunc;
126 ConvertToVariantFunction toVariantFunc;
129 typedef QHash<int, RuntimeConversion> RuntimeConversionTable;
130 Q_GLOBAL_STATIC(RuntimeConversionTable, customRuntimeConversions)
132 void registerCustomType(int qtMetaTypeId, ConvertToVariantFunction toVariantFunc, ConvertToJSValueFunction toJSValueFunc)
134 RuntimeConversion conversion;
135 conversion.toJSValueFunc = toJSValueFunc;
136 conversion.toVariantFunc = toVariantFunc;
137 customRuntimeConversions()->insert(qtMetaTypeId, conversion);
140 static bool isJSUint8ClampedArray(JSValue val)
142 return val.isCell() && val.inherits(&JSUint8ClampedArray::s_info);
145 static JSRealType valueRealType(ExecState* exec, JSValue val)
149 else if (val.isString())
151 else if (val.isBoolean())
153 else if (val.isNull())
155 else if (isJSUint8ClampedArray(val))
156 return JSUint8ClampedArray;
157 else if (val.isObject()) {
158 JSObject *object = val.toObject(exec);
159 if (object->inherits(&RuntimeArray::s_info)) // RuntimeArray 'inherits' from Array, but not in C++
161 else if (object->inherits(&JSArray::s_info))
163 else if (object->inherits(&DateInstance::s_info))
165 else if (object->inherits(&RegExpObject::s_info))
167 else if (object->inherits(&RuntimeObject::s_info))
172 return String; // I don't know.
175 QVariant convertValueToQVariant(ExecState*, JSValue, QMetaType::Type, int*, HashSet<JSObject*>*, int);
177 static QVariantMap convertValueToQVariantMap(ExecState* exec, JSObject* object, HashSet<JSObject*>* visitedObjects, int recursionLimit)
179 Q_ASSERT(!exec->hadException());
181 PropertyNameArray properties(exec);
182 object->methodTable()->getPropertyNames(object, exec, properties, ExcludeDontEnumProperties);
183 PropertyNameArray::const_iterator it = properties.begin();
187 while (it != properties.end()) {
188 if (object->propertyIsEnumerable(exec, *it)) {
189 JSValue val = object->get(exec, *it);
190 if (exec->hadException())
191 exec->clearException();
193 QVariant v = convertValueToQVariant(exec, val, QMetaType::Void, &objdist, visitedObjects, recursionLimit);
195 UString ustring = (*it).ustring();
196 QString id = QString((const QChar*)ustring.impl()->characters(), ustring.length());
197 result.insert(id, v);
206 QVariant convertValueToQVariant(ExecState* exec, JSValue value, QMetaType::Type hint, int *distance, HashSet<JSObject*>* visitedObjects, int recursionLimit)
210 if (!value || !recursionLimit)
213 JSObject* object = 0;
214 if (value.isObject()) {
215 object = value.toObject(exec);
216 if (visitedObjects->contains(object))
219 visitedObjects->add(object);
222 // check magic pointer values before dereferencing value
224 || (value == jsUndefined()
225 && hint != QMetaType::QString
226 && hint != (QMetaType::Type) qMetaTypeId<QVariant>())) {
232 JSLock lock(SilenceAssertionsOnly);
233 JSRealType type = valueRealType(exec, value);
234 if (hint == QMetaType::Void) {
237 hint = QMetaType::Double;
240 hint = QMetaType::Bool;
244 hint = QMetaType::QString;
247 hint = QMetaType::QDateTime;
250 hint = QMetaType::QRegExp;
253 if (object->inherits(&NumberObject::s_info))
254 hint = QMetaType::Double;
255 else if (object->inherits(&BooleanObject::s_info))
256 hint = QMetaType::Bool;
258 hint = QMetaType::QVariantMap;
261 hint = QMetaType::QObjectStar;
263 case JSUint8ClampedArray:
264 hint = QMetaType::QByteArray;
268 hint = QMetaType::QVariantList;
273 qConvDebug() << "convertValueToQVariant: jstype is " << type << ", hint is" << hint;
275 if (value == jsNull()
276 && hint != QMetaType::QObjectStar
277 && hint != QMetaType::VoidStar
278 && hint != QMetaType::QString
279 && hint != (QMetaType::Type) qMetaTypeId<QVariant>()) {
288 case QMetaType::Bool:
289 if (type == Object && object->inherits(&BooleanObject::s_info))
290 ret = QVariant(asBooleanObject(value)->internalValue().toBoolean());
292 ret = QVariant(value.toBoolean());
300 case QMetaType::UInt:
301 case QMetaType::Long:
302 case QMetaType::ULong:
303 case QMetaType::LongLong:
304 case QMetaType::ULongLong:
305 case QMetaType::Short:
306 case QMetaType::UShort:
307 case QMetaType::Float:
308 case QMetaType::Double:
309 ret = QVariant(value.toNumber(exec));
310 ret.convert((QVariant::Type)hint);
311 if (type == Number) {
313 case QMetaType::Double:
316 case QMetaType::Float:
319 case QMetaType::LongLong:
320 case QMetaType::ULongLong:
323 case QMetaType::Long:
324 case QMetaType::ULong:
328 case QMetaType::UInt:
331 case QMetaType::Short:
332 case QMetaType::UShort:
345 case QMetaType::QChar:
346 if (type == Number || type == Boolean) {
347 ret = QVariant(QChar((ushort)value.toNumber(exec)));
353 UString str = value.toString(exec)->value(exec);
354 ret = QVariant(QChar(str.length() ? *(const ushort*)str.impl()->characters() : 0));
362 case QMetaType::QString: {
363 if (value.isUndefinedOrNull()) {
368 UString ustring = value.toString(exec)->value(exec);
369 ret = QVariant(QString((const QChar*)ustring.impl()->characters(), ustring.length()));
378 case QMetaType::QVariantMap:
379 if (type == Object || type == Array || type == RTArray) {
380 ret = QVariant(convertValueToQVariantMap(exec, object, visitedObjects, recursionLimit));
381 // Those types can still have perfect matches, e.g. 'bool' if value is a Boolean Object.
386 case QMetaType::QVariantList:
387 if (type == RTArray) {
388 RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
391 int len = rtarray->getLength();
393 qConvDebug() << "converting a " << len << " length Array";
394 for (int i = 0; i < len; ++i) {
395 JSValue val = rtarray->getConcreteArray()->valueAt(exec, i);
396 result.append(convertValueToQVariant(exec, val, QMetaType::Void, &objdist, visitedObjects, recursionLimit));
398 qConvDebug() << "Failed converting element at index " << i;
399 break; // Failed converting a list entry, so fail the array
404 ret = QVariant(result);
406 } else if (type == Array) {
407 JSArray* array = static_cast<JSArray*>(object);
410 int len = array->length();
412 qConvDebug() << "converting a " << len << " length Array";
413 for (int i = 0; i < len; ++i) {
414 JSValue val = array->get(exec, i);
415 result.append(convertValueToQVariant(exec, val, QMetaType::Void, &objdist, visitedObjects, recursionLimit));
417 qConvDebug() << "Failed converting element at index " << i;
418 break; // Failed converting a list entry, so fail the array
423 ret = QVariant(result);
426 // Make a single length array
428 qConvDebug() << "making a single length variantlist";
429 QVariant var = convertValueToQVariant(exec, value, QMetaType::Void, &objdist, visitedObjects, recursionLimit);
433 ret = QVariant(result);
436 qConvDebug() << "failed making single length varlist";
441 case QMetaType::QStringList: {
442 if (type == RTArray) {
443 RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
446 int len = rtarray->getLength();
447 for (int i = 0; i < len; ++i) {
448 JSValue val = rtarray->getConcreteArray()->valueAt(exec, i);
449 UString ustring = val.toString(exec)->value(exec);
450 QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
452 result.append(qstring);
455 ret = QVariant(result);
456 } else if (type == Array) {
457 JSArray* array = static_cast<JSArray*>(object);
460 int len = array->length();
461 for (int i = 0; i < len; ++i) {
462 JSValue val = array->get(exec, i);
463 UString ustring = val.toString(exec)->value(exec);
464 QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
466 result.append(qstring);
469 ret = QVariant(result);
471 // Make a single length array
472 UString ustring = value.toString(exec)->value(exec);
473 QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
475 result.append(qstring);
476 ret = QVariant(result);
482 case QMetaType::QByteArray: {
483 if (type == JSUint8ClampedArray) {
484 WTF::Uint8ClampedArray* arr = toUint8ClampedArray(value);
485 ret = QVariant(QByteArray(reinterpret_cast<const char*>(arr->data()), arr->length()));
488 UString ustring = value.toString(exec)->value(exec);
489 ret = QVariant(QString((const QChar*)ustring.impl()->characters(), ustring.length()).toLatin1());
498 case QMetaType::QDateTime:
499 case QMetaType::QDate:
500 case QMetaType::QTime:
502 DateInstance* date = static_cast<DateInstance*>(object);
503 GregorianDateTime gdt;
504 msToGregorianDateTime(exec, date->internalNumber(), true, gdt);
505 if (hint == QMetaType::QDateTime) {
506 ret = QDateTime(QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay), QTime(gdt.hour, gdt.minute, gdt.second), Qt::UTC);
508 } else if (hint == QMetaType::QDate) {
509 ret = QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay);
512 ret = QTime(gdt.hour + 1900, gdt.minute, gdt.second);
515 } else if (type == Number) {
516 double b = value.toNumber(exec);
517 GregorianDateTime gdt;
518 msToGregorianDateTime(exec, b, true, gdt);
519 if (hint == QMetaType::QDateTime) {
520 ret = QDateTime(QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay), QTime(gdt.hour, gdt.minute, gdt.second), Qt::UTC);
522 } else if (hint == QMetaType::QDate) {
523 ret = QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay);
526 ret = QTime(gdt.hour, gdt.minute, gdt.second);
529 #ifndef QT_NO_DATESTRING
530 } else if (type == String) {
531 UString ustring = value.toString(exec)->value(exec);
532 QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
534 if (hint == QMetaType::QDateTime) {
535 QDateTime dt = QDateTime::fromString(qstring, Qt::ISODate);
537 dt = QDateTime::fromString(qstring, Qt::TextDate);
539 dt = QDateTime::fromString(qstring, Qt::SystemLocaleDate);
541 dt = QDateTime::fromString(qstring, Qt::LocaleDate);
546 } else if (hint == QMetaType::QDate) {
547 QDate dt = QDate::fromString(qstring, Qt::ISODate);
549 dt = QDate::fromString(qstring, Qt::TextDate);
551 dt = QDate::fromString(qstring, Qt::SystemLocaleDate);
553 dt = QDate::fromString(qstring, Qt::LocaleDate);
559 QTime dt = QTime::fromString(qstring, Qt::ISODate);
561 dt = QTime::fromString(qstring, Qt::TextDate);
563 dt = QTime::fromString(qstring, Qt::SystemLocaleDate);
565 dt = QTime::fromString(qstring, Qt::LocaleDate);
571 #endif // QT_NO_DATESTRING
575 case QMetaType::QRegExp:
576 if (type == RegExp) {
578 RegExpObject *re = static_cast<RegExpObject*>(object);
580 // Attempt to convert.. a bit risky
581 UString ustring = value.toString(exec)->value(exec);
582 QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
584 // this is of the form '/xxxxxx/i'
585 int firstSlash = qstring.indexOf(QLatin1Char('/'));
586 int lastSlash = qstring.lastIndexOf(QLatin1Char('/'));
587 if (firstSlash >=0 && lastSlash > firstSlash) {
590 realRe.setPattern(qstring.mid(firstSlash + 1, lastSlash - firstSlash - 1));
592 if (qstring.mid(lastSlash + 1).contains(QLatin1Char('i')))
593 realRe.setCaseSensitivity(Qt::CaseInsensitive);
595 ret = QVariant::fromValue(realRe);
598 qConvDebug() << "couldn't parse a JS regexp";
600 } else if (type == String) {
601 UString ustring = value.toString(exec)->value(exec);
602 QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
606 ret = QVariant::fromValue(re);
612 case QMetaType::QObjectStar:
614 QtInstance* qtinst = QtInstance::getInstance(object);
616 if (qtinst->getObject()) {
617 qConvDebug() << "found instance, with object:" << (void*) qtinst->getObject();
618 ret = QVariant::fromValue(qtinst->getObject());
622 qConvDebug() << "can't convert deleted qobject";
625 qConvDebug() << "wasn't a qtinstance";
627 } else if (type == Null) {
628 QObject* nullobj = 0;
629 ret = QVariant::fromValue(nullobj);
632 qConvDebug() << "previous type was not an object:" << type;
636 case QMetaType::VoidStar:
638 QtInstance* qtinst = QtInstance::getInstance(object);
640 if (qtinst->getObject()) {
641 qConvDebug() << "found instance, with object:" << (void*) qtinst->getObject();
642 ret = QVariant::fromValue((void *)qtinst->getObject());
646 qConvDebug() << "can't convert deleted qobject";
649 qConvDebug() << "wasn't a qtinstance";
651 } else if (type == Null) {
652 ret = QVariant::fromValue((void*)0);
654 } else if (type == Number) {
655 // I don't think that converting a double to a pointer is a wise
656 // move. Except maybe 0.
657 qConvDebug() << "got number for void * - not converting, seems unsafe:" << value.toNumber(exec);
659 qConvDebug() << "void* - unhandled type" << type;
664 // Non const type ids
665 if (hint == (QMetaType::Type) qMetaTypeId<QObjectList>())
667 if (type == RTArray) {
668 RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
671 int len = rtarray->getLength();
672 for (int i = 0; i < len; ++i) {
673 JSValue val = rtarray->getConcreteArray()->valueAt(exec, i);
675 QVariant item = convertValueToQVariant(exec, val, QMetaType::QObjectStar, &itemdist, visitedObjects, recursionLimit);
677 result.append(item.value<QObject*>());
681 // If we didn't fail conversion
682 if (result.count() == len) {
684 ret = QVariant::fromValue(result);
686 } else if (type == Array) {
687 JSObject* object = value.toObject(exec);
688 JSArray* array = static_cast<JSArray *>(object);
690 int len = array->length();
691 for (int i = 0; i < len; ++i) {
692 JSValue val = array->get(exec, i);
694 QVariant item = convertValueToQVariant(exec, val, QMetaType::QObjectStar, &itemdist, visitedObjects, recursionLimit);
696 result.append(item.value<QObject*>());
700 // If we didn't fail conversion
701 if (result.count() == len) {
703 ret = QVariant::fromValue(result);
706 // Make a single length array
709 QVariant item = convertValueToQVariant(exec, value, QMetaType::QObjectStar, &itemdist, visitedObjects, recursionLimit);
711 result.append(item.value<QObject*>());
713 ret = QVariant::fromValue(result);
717 } else if (hint == (QMetaType::Type) qMetaTypeId<QList<int> >()) {
718 if (type == RTArray) {
719 RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
722 int len = rtarray->getLength();
723 for (int i = 0; i < len; ++i) {
724 JSValue val = rtarray->getConcreteArray()->valueAt(exec, i);
726 QVariant item = convertValueToQVariant(exec, val, QMetaType::Int, &itemdist, visitedObjects, recursionLimit);
728 result.append(item.value<int>());
732 // If we didn't fail conversion
733 if (result.count() == len) {
735 ret = QVariant::fromValue(result);
737 } else if (type == Array) {
738 JSArray* array = static_cast<JSArray *>(object);
741 int len = array->length();
742 for (int i = 0; i < len; ++i) {
743 JSValue val = array->get(exec, i);
745 QVariant item = convertValueToQVariant(exec, val, QMetaType::Int, &itemdist, visitedObjects, recursionLimit);
747 result.append(item.value<int>());
751 // If we didn't fail conversion
752 if (result.count() == len) {
754 ret = QVariant::fromValue(result);
757 // Make a single length array
760 QVariant item = convertValueToQVariant(exec, value, QMetaType::Int, &itemdist, visitedObjects, recursionLimit);
762 result.append(item.value<int>());
764 ret = QVariant::fromValue(result);
768 } else if (QtPixmapInstance::canHandle(static_cast<QMetaType::Type>(hint))) {
769 ret = QtPixmapInstance::variantFromObject(object, static_cast<QMetaType::Type>(hint));
770 } else if (customRuntimeConversions()->contains(hint)) {
771 ret = customRuntimeConversions()->value(hint).toVariantFunc(object, &dist, visitedObjects);
774 } else if (hint == (QMetaType::Type) qMetaTypeId<QVariant>()) {
775 if (value.isUndefinedOrNull()) {
780 if (type == Object) {
781 // Since we haven't really visited this object yet, we remove it
782 visitedObjects->remove(object);
785 // And then recurse with the autodetect flag
786 ret = convertValueToQVariant(exec, value, QMetaType::Void, distance, visitedObjects, recursionLimit);
804 QVariant convertValueToQVariant(ExecState* exec, JSValue value, QMetaType::Type hint, int *distance)
806 const int recursionLimit = 200;
807 HashSet<JSObject*> visitedObjects;
808 return convertValueToQVariant(exec, value, hint, distance, &visitedObjects, recursionLimit);
811 JSValue convertQVariantToValue(ExecState* exec, PassRefPtr<RootObject> root, const QVariant& variant)
813 // Variants with QObject * can be isNull but not a null pointer
814 // An empty QString variant is also null
815 QMetaType::Type type = (QMetaType::Type) variant.userType();
817 qConvDebug() << "convertQVariantToValue: metatype:" << type << ", isnull: " << variant.isNull();
818 if (variant.isNull() &&
819 type != QMetaType::QObjectStar &&
820 type != QMetaType::VoidStar &&
821 type != QMetaType::QWidgetStar &&
822 type != QMetaType::QString) {
826 JSLock lock(SilenceAssertionsOnly);
828 if (type == QMetaType::Bool)
829 return jsBoolean(variant.toBool());
831 if (type == QMetaType::Int ||
832 type == QMetaType::UInt ||
833 type == QMetaType::Long ||
834 type == QMetaType::ULong ||
835 type == QMetaType::LongLong ||
836 type == QMetaType::ULongLong ||
837 type == QMetaType::Short ||
838 type == QMetaType::UShort ||
839 type == QMetaType::Float ||
840 type == QMetaType::Double)
841 return jsNumber(variant.toDouble());
843 if (type == QMetaType::QRegExp) {
844 QRegExp re = variant.value<QRegExp>();
847 UString pattern((UChar*)re.pattern().utf16(), re.pattern().length());
848 RegExpFlags flags = (re.caseSensitivity() == Qt::CaseInsensitive) ? FlagIgnoreCase : NoFlags;
850 JSC::RegExp* regExp = JSC::RegExp::create(exec->globalData(), pattern, flags);
851 if (regExp->isValid())
852 return RegExpObject::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->regExpStructure(), regExp);
857 if (type == QMetaType::QDateTime ||
858 type == QMetaType::QDate ||
859 type == QMetaType::QTime) {
861 QDate date = QDate::currentDate();
862 QTime time(0,0,0); // midnight
864 if (type == QMetaType::QDate)
865 date = variant.value<QDate>();
866 else if (type == QMetaType::QTime)
867 time = variant.value<QTime>();
869 QDateTime dt = variant.value<QDateTime>().toLocalTime();
874 // Dates specified this way are in local time (we convert DateTimes above)
875 GregorianDateTime dt;
876 dt.year = date.year() - 1900;
877 dt.month = date.month() - 1;
878 dt.monthDay = date.day();
879 dt.hour = time.hour();
880 dt.minute = time.minute();
881 dt.second = time.second();
883 double ms = gregorianDateTimeToMS(exec, dt, time.msec(), /*inputIsUTC*/ false);
885 return DateInstance::create(exec, exec->lexicalGlobalObject()->dateStructure(), trunc(ms));
888 if (type == QMetaType::QByteArray) {
889 QByteArray qtByteArray = variant.value<QByteArray>();
890 WTF::RefPtr<WTF::Uint8ClampedArray> wtfByteArray = WTF::Uint8ClampedArray::createUninitialized(qtByteArray.length());
891 memcpy(wtfByteArray->data(), qtByteArray.constData(), qtByteArray.length());
892 return toJS(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), wtfByteArray.get());
895 if (type == QMetaType::QObjectStar || type == QMetaType::QWidgetStar) {
896 QObject* obj = variant.value<QObject*>();
899 return QtInstance::getQtInstance(obj, root, QScriptEngine::QtOwnership)->createRuntimeObject(exec);
902 if (QtPixmapInstance::canHandle(static_cast<QMetaType::Type>(variant.type())))
903 return QtPixmapInstance::createPixmapRuntimeObject(exec, root, variant);
905 if (customRuntimeConversions()->contains(type)) {
906 if (!root->globalObject()->inherits(&JSDOMWindow::s_info))
907 return jsUndefined();
909 Document* document = (static_cast<JSDOMWindow*>(root->globalObject()))->impl()->document();
911 return jsUndefined();
912 return customRuntimeConversions()->value(type).toJSValueFunc(exec, toJSDOMGlobalObject(document, exec), variant);
915 if (type == QMetaType::QVariantMap) {
916 // create a new object, and stuff properties into it
917 JSObject* ret = constructEmptyObject(exec);
918 QVariantMap map = variant.value<QVariantMap>();
919 QVariantMap::const_iterator i = map.constBegin();
920 while (i != map.constEnd()) {
922 JSValue val = convertQVariantToValue(exec, root.get(), i.value());
924 PutPropertySlot slot;
925 ret->methodTable()->put(ret, exec, Identifier(&exec->globalData(), reinterpret_cast_ptr<const UChar *>(s.constData()), s.length()), val, slot);
935 if (type == QMetaType::QVariantList) {
936 QVariantList vl = variant.toList();
937 qConvDebug() << "got a " << vl.count() << " length list:" << vl;
938 return RuntimeArray::create(exec, new QtArray<QVariant>(vl, QMetaType::Void, root));
939 } else if (type == QMetaType::QStringList) {
940 QStringList sl = variant.value<QStringList>();
941 return RuntimeArray::create(exec, new QtArray<QString>(sl, QMetaType::QString, root));
942 } else if (type == (QMetaType::Type) qMetaTypeId<QObjectList>()) {
943 QObjectList ol= variant.value<QObjectList>();
944 return RuntimeArray::create(exec, new QtArray<QObject*>(ol, QMetaType::QObjectStar, root));
945 } else if (type == (QMetaType::Type)qMetaTypeId<QList<int> >()) {
946 QList<int> il= variant.value<QList<int> >();
947 return RuntimeArray::create(exec, new QtArray<int>(il, QMetaType::Int, root));
950 if (type == (QMetaType::Type)qMetaTypeId<QVariant>()) {
951 QVariant real = variant.value<QVariant>();
952 qConvDebug() << "real variant is:" << real;
953 return convertQVariantToValue(exec, root, real);
956 qConvDebug() << "fallback path for" << variant << variant.userType();
958 QString string = variant.toString();
959 UString ustring((UChar*)string.utf16(), string.length());
960 return jsString(exec, ustring);
966 #define QW_D(Class) Class##Data* d = d_func()
967 #define QW_DS(Class,Instance) Class##Data* d = Instance->d_func()
969 const ClassInfo QtRuntimeMethod::s_info = { "QtRuntimeMethod", &InternalFunction::s_info, 0, 0, CREATE_METHOD_TABLE(QtRuntimeMethod) };
971 QtRuntimeMethod::QtRuntimeMethod(QtRuntimeMethodData* dd, ExecState* exec, Structure* structure, const UString& identifier)
972 : InternalFunction(exec->lexicalGlobalObject(), structure)
977 void QtRuntimeMethod::finishCreation(ExecState* exec, const UString& identifier, PassRefPtr<QtInstance> instance)
979 Base::finishCreation(exec->globalData(), identifier);
980 QW_D(QtRuntimeMethod);
981 d->m_instance = instance;
982 d->m_finalizer = PassWeak<QtRuntimeMethod>(this, d);
985 QtRuntimeMethod::~QtRuntimeMethod()
990 void QtRuntimeMethod::destroy(JSCell* cell)
992 jsCast<QtRuntimeMethod*>(cell)->QtRuntimeMethod::~QtRuntimeMethod();
997 QtRuntimeMethodData::~QtRuntimeMethodData()
1001 void QtRuntimeMethodData::finalize(Handle<Unknown> value, void*)
1003 m_instance->removeCachedMethod(static_cast<JSObject*>(value.get().asCell()));
1006 QtRuntimeMetaMethodData::~QtRuntimeMetaMethodData()
1011 QtRuntimeConnectionMethodData::~QtRuntimeConnectionMethodData()
1018 // Type conversion metadata (from QtScript originally)
1019 class QtMethodMatchType
1032 : m_kind(Invalid) { }
1037 QMetaType::Type typeId() const;
1039 bool isValid() const
1040 { return (m_kind != Invalid); }
1042 bool isVariant() const
1043 { return (m_kind == Variant); }
1045 bool isMetaType() const
1046 { return (m_kind == MetaType); }
1048 bool isUnresolved() const
1049 { return (m_kind == Unresolved); }
1051 bool isMetaEnum() const
1052 { return (m_kind == MetaEnum); }
1054 QByteArray name() const;
1056 int enumeratorIndex() const
1057 { Q_ASSERT(isMetaEnum()); return m_typeId; }
1059 static QtMethodMatchType variant()
1060 { return QtMethodMatchType(Variant); }
1062 static QtMethodMatchType metaType(int typeId, const QByteArray &name)
1063 { return QtMethodMatchType(MetaType, typeId, name); }
1065 static QtMethodMatchType metaEnum(int enumIndex, const QByteArray &name)
1066 { return QtMethodMatchType(MetaEnum, enumIndex, name); }
1068 static QtMethodMatchType unresolved(const QByteArray &name)
1069 { return QtMethodMatchType(Unresolved, /*typeId=*/0, name); }
1072 QtMethodMatchType(Kind kind, int typeId = 0, const QByteArray &name = QByteArray())
1073 : m_kind(kind), m_typeId(typeId), m_name(name) { }
1080 QMetaType::Type QtMethodMatchType::typeId() const
1083 return (QMetaType::Type) QMetaType::type("QVariant");
1084 return (QMetaType::Type) (isMetaEnum() ? QMetaType::Int : m_typeId);
1087 QByteArray QtMethodMatchType::name() const
1089 if (!m_name.isEmpty())
1091 else if (m_kind == Variant)
1093 return QByteArray();
1096 struct QtMethodMatchData
1100 QVector<QtMethodMatchType> types;
1101 QVarLengthArray<QVariant, 10> args;
1103 QtMethodMatchData(int dist, int idx, QVector<QtMethodMatchType> typs,
1104 const QVarLengthArray<QVariant, 10> &as)
1105 : matchDistance(dist), index(idx), types(typs), args(as) { }
1109 bool isValid() const
1110 { return (index != -1); }
1112 int firstUnresolvedIndex() const
1114 for (int i=0; i < types.count(); i++) {
1115 if (types.at(i).isUnresolved())
1122 static int indexOfMetaEnum(const QMetaObject *meta, const QByteArray &str)
1126 int scopeIdx = str.indexOf("::");
1127 if (scopeIdx != -1) {
1128 scope = str.left(scopeIdx);
1129 name = str.mid(scopeIdx + 2);
1133 for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
1134 QMetaEnum m = meta->enumerator(i);
1135 if ((m.name() == name)/* && (scope.isEmpty() || (m.scope() == scope))*/)
1141 // Helper function for resolving methods
1142 // Largely based on code in QtScript for compatibility reasons
1143 static int findMethodIndex(ExecState* exec,
1144 const QMetaObject* meta,
1145 const QByteArray& signature,
1147 QVarLengthArray<QVariant, 10> &vars,
1151 QList<int> matchingIndices;
1153 bool overloads = !signature.contains('(');
1155 int count = meta->methodCount();
1156 for (int i = count - 1; i >= 0; --i) {
1157 const QMetaMethod m = meta->method(i);
1159 // Don't choose private methods
1160 if (m.access() == QMetaMethod::Private && !allowPrivate)
1163 // try and find all matching named methods
1164 if (!overloads && m.methodSignature() == signature)
1165 matchingIndices.append(i);
1166 else if (overloads && m.name() == signature)
1167 matchingIndices.append(i);
1170 int chosenIndex = -1;
1172 QVector<QtMethodMatchType> chosenTypes;
1174 QVarLengthArray<QVariant, 10> args;
1175 QVector<QtMethodMatchData> candidates;
1176 QVector<QtMethodMatchData> unresolved;
1177 QVector<int> tooFewArgs;
1178 QVector<int> conversionFailed;
1180 foreach(int index, matchingIndices) {
1181 QMetaMethod method = meta->method(index);
1183 QVector<QtMethodMatchType> types;
1184 bool unresolvedTypes = false;
1186 // resolve return type
1187 QByteArray returnTypeName = method.typeName();
1188 int rtype = method.returnType();
1189 if (rtype == QMetaType::UnknownType) {
1190 if (returnTypeName.endsWith('*')) {
1191 types.append(QtMethodMatchType::metaType(QMetaType::VoidStar, returnTypeName));
1193 int enumIndex = indexOfMetaEnum(meta, returnTypeName);
1194 if (enumIndex != -1)
1195 types.append(QtMethodMatchType::metaEnum(enumIndex, returnTypeName));
1197 unresolvedTypes = true;
1198 types.append(QtMethodMatchType::unresolved(returnTypeName));
1202 if (rtype == QMetaType::QVariant)
1203 types.append(QtMethodMatchType::variant());
1205 types.append(QtMethodMatchType::metaType(rtype, returnTypeName));
1208 // resolve argument types
1209 QList<QByteArray> parameterTypeNames = method.parameterTypes();
1210 for (int i = 0; i < parameterTypeNames.count(); ++i) {
1211 QByteArray argTypeName = parameterTypeNames.at(i);
1212 int atype = method.parameterType(i);
1213 if (atype == QMetaType::UnknownType) {
1214 int enumIndex = indexOfMetaEnum(meta, argTypeName);
1215 if (enumIndex != -1)
1216 types.append(QtMethodMatchType::metaEnum(enumIndex, argTypeName));
1218 unresolvedTypes = true;
1219 types.append(QtMethodMatchType::unresolved(argTypeName));
1222 if (atype == QMetaType::QVariant)
1223 types.append(QtMethodMatchType::variant());
1225 types.append(QtMethodMatchType::metaType(atype, argTypeName));
1229 // If the native method requires more arguments than what was passed from JavaScript
1230 if (exec->argumentCount() + 1 < static_cast<unsigned>(types.count())) {
1231 qMatchDebug() << "Match:too few args for" << method.methodSignature();
1232 tooFewArgs.append(index);
1236 if (unresolvedTypes) {
1237 qMatchDebug() << "Match:unresolved arg types for" << method.methodSignature();
1238 // remember it so we can give an error message later, if necessary
1239 unresolved.append(QtMethodMatchData(/*matchDistance=*/INT_MAX, index,
1240 types, QVarLengthArray<QVariant, 10>()));
1244 // Now convert arguments
1245 if (args.count() != types.count())
1246 args.resize(types.count());
1248 QtMethodMatchType retType = types[0];
1249 if (retType.typeId() != QMetaType::Void)
1250 args[0] = QVariant(retType.typeId(), (void *)0); // the return value
1252 bool converted = true;
1253 int matchDistance = 0;
1254 for (unsigned i = 0; converted && i + 1 < static_cast<unsigned>(types.count()); ++i) {
1255 JSValue arg = i < exec->argumentCount() ? exec->argument(i) : jsUndefined();
1257 int argdistance = -1;
1258 QVariant v = convertValueToQVariant(exec, arg, types.at(i+1).typeId(), &argdistance);
1259 if (argdistance >= 0) {
1260 matchDistance += argdistance;
1263 qMatchDebug() << "failed to convert argument " << i << "type" << types.at(i+1).typeId() << QMetaType::typeName(types.at(i+1).typeId());
1268 qMatchDebug() << "Match: " << method.methodSignature() << (converted ? "converted":"failed to convert") << "distance " << matchDistance;
1271 if ((exec->argumentCount() + 1 == static_cast<unsigned>(types.count()))
1272 && (matchDistance == 0)) {
1273 // perfect match, use this one
1274 chosenIndex = index;
1277 QtMethodMatchData currentMatch(matchDistance, index, types, args);
1278 if (candidates.isEmpty()) {
1279 candidates.append(currentMatch);
1281 QtMethodMatchData bestMatchSoFar = candidates.at(0);
1282 if ((args.count() > bestMatchSoFar.args.count())
1283 || ((args.count() == bestMatchSoFar.args.count())
1284 && (matchDistance <= bestMatchSoFar.matchDistance))) {
1285 candidates.prepend(currentMatch);
1287 candidates.append(currentMatch);
1292 conversionFailed.append(index);
1299 if (chosenIndex == -1 && candidates.count() == 0) {
1300 // No valid functions at all - format an error message
1301 if (!conversionFailed.isEmpty()) {
1302 QString message = QString::fromLatin1("incompatible type of argument(s) in call to %0(); candidates were\n")
1303 .arg(QString::fromLatin1(signature));
1304 for (int i = 0; i < conversionFailed.size(); ++i) {
1306 message += QLatin1String("\n");
1307 QMetaMethod mtd = meta->method(conversionFailed.at(i));
1308 message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.methodSignature()));
1310 *pError = throwError(exec, createTypeError(exec, message.toLatin1().constData()));
1311 } else if (!unresolved.isEmpty()) {
1312 QtMethodMatchData argsInstance = unresolved.first();
1313 int unresolvedIndex = argsInstance.firstUnresolvedIndex();
1314 Q_ASSERT(unresolvedIndex != -1);
1315 QtMethodMatchType unresolvedType = argsInstance.types.at(unresolvedIndex);
1316 QString message = QString::fromLatin1("cannot call %0(): unknown type `%1'")
1317 .arg(QString::fromLatin1(signature))
1318 .arg(QLatin1String(unresolvedType.name()));
1319 *pError = throwError(exec, createTypeError(exec, message.toLatin1().constData()));
1321 QString message = QString::fromLatin1("too few arguments in call to %0(); candidates are\n")
1322 .arg(QString::fromLatin1(signature));
1323 for (int i = 0; i < tooFewArgs.size(); ++i) {
1325 message += QLatin1String("\n");
1326 QMetaMethod mtd = meta->method(tooFewArgs.at(i));
1327 message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.methodSignature()));
1329 *pError = throwError(exec, createSyntaxError(exec, message.toLatin1().constData()));
1333 if (chosenIndex == -1 && candidates.count() > 0) {
1334 QtMethodMatchData bestMatch = candidates.at(0);
1335 if ((candidates.size() > 1)
1336 && (bestMatch.args.count() == candidates.at(1).args.count())
1337 && (bestMatch.matchDistance == candidates.at(1).matchDistance)) {
1339 QString message = QString::fromLatin1("ambiguous call of overloaded function %0(); candidates were\n")
1340 .arg(QLatin1String(signature));
1341 for (int i = 0; i < candidates.size(); ++i) {
1342 // Only candidate for overload if argument count and match distance is same as best match
1343 if (candidates.at(i).args.count() == bestMatch.args.count()
1344 || candidates.at(i).matchDistance == bestMatch.matchDistance) {
1346 message += QLatin1String("\n");
1347 QMetaMethod mtd = meta->method(candidates.at(i).index);
1348 message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.methodSignature()));
1351 *pError = throwError(exec, createTypeError(exec, message.toLatin1().constData()));
1353 chosenIndex = bestMatch.index;
1354 args = bestMatch.args;
1358 if (chosenIndex != -1) {
1359 /* Copy the stuff over */
1361 vars.resize(args.count());
1362 for (i=0; i < args.count(); i++) {
1364 vvars[i] = vars[i].data();
1371 // Signals are not fuzzy matched as much as methods
1372 static int findSignalIndex(const QMetaObject* meta, int initialIndex, QByteArray signature)
1374 int index = initialIndex;
1375 QMetaMethod method = meta->method(index);
1376 bool overloads = !signature.contains('(');
1377 if (overloads && (method.attributes() & QMetaMethod::Cloned)) {
1378 // find the most general method
1380 method = meta->method(--index);
1381 } while (method.attributes() & QMetaMethod::Cloned);
1386 const ClassInfo QtRuntimeMetaMethod::s_info = { "QtRuntimeMethod", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(QtRuntimeMetaMethod) };
1388 QtRuntimeMetaMethod::QtRuntimeMetaMethod(ExecState* exec, Structure* structure, const UString& identifier)
1389 : QtRuntimeMethod (new QtRuntimeMetaMethodData(), exec, structure, identifier)
1393 void QtRuntimeMetaMethod::finishCreation(ExecState* exec, const UString& identifier, PassRefPtr<QtInstance> instance, int index, const QByteArray& signature, bool allowPrivate)
1395 Base::finishCreation(exec, identifier, instance);
1396 QW_D(QtRuntimeMetaMethod);
1397 d->m_signature = signature;
1399 d->m_allowPrivate = allowPrivate;
1402 void QtRuntimeMetaMethod::visitChildren(JSCell* cell, SlotVisitor& visitor)
1404 QtRuntimeMetaMethod* thisObject = jsCast<QtRuntimeMetaMethod*>(cell);
1405 QtRuntimeMethod::visitChildren(thisObject, visitor);
1406 QtRuntimeMetaMethodData* d = thisObject->d_func();
1408 visitor.append(&d->m_connect);
1409 if (d->m_disconnect)
1410 visitor.append(&d->m_disconnect);
1413 EncodedJSValue QtRuntimeMetaMethod::call(ExecState* exec)
1415 QtRuntimeMetaMethodData* d = static_cast<QtRuntimeMetaMethod *>(exec->callee())->d_func();
1417 // We're limited to 10 args
1418 if (exec->argumentCount() > 10)
1419 return JSValue::encode(jsUndefined());
1421 // We have to pick a method that matches..
1422 JSLock lock(SilenceAssertionsOnly);
1424 QObject *obj = d->m_instance->getObject();
1426 QVarLengthArray<QVariant, 10> vargs;
1430 JSObject* errorObj = 0;
1431 if ((methodIndex = findMethodIndex(exec, obj->metaObject(), d->m_signature, d->m_allowPrivate, vargs, (void **)qargs, &errorObj)) != -1) {
1432 if (QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, methodIndex, qargs) >= 0)
1433 return JSValue::encode(jsUndefined());
1435 if (vargs[0].isValid())
1436 return JSValue::encode(convertQVariantToValue(exec, d->m_instance->rootObject(), vargs[0]));
1440 return JSValue::encode(errorObj);
1442 return throwVMError(exec, createError(exec, "cannot call function of deleted QObject"));
1445 // void functions return undefined
1446 return JSValue::encode(jsUndefined());
1449 CallType QtRuntimeMetaMethod::getCallData(JSCell*, CallData& callData)
1451 callData.native.function = call;
1452 return CallTypeHost;
1455 bool QtRuntimeMetaMethod::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
1457 QtRuntimeMetaMethod* thisObject = jsCast<QtRuntimeMetaMethod*>(cell);
1458 if (propertyName == Identifier(exec, "connect")) {
1459 slot.setCustom(thisObject, thisObject->connectGetter);
1462 if (propertyName == Identifier(exec, "disconnect")) {
1463 slot.setCustom(thisObject, thisObject->disconnectGetter);
1466 if (propertyName == exec->propertyNames().length) {
1467 slot.setCustom(thisObject, thisObject->lengthGetter);
1471 return QtRuntimeMethod::getOwnPropertySlot(thisObject, exec, propertyName, slot);
1474 bool QtRuntimeMetaMethod::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
1476 QtRuntimeMetaMethod* thisObject = jsCast<QtRuntimeMetaMethod*>(object);
1477 if (propertyName == Identifier(exec, "connect")) {
1479 slot.setCustom(thisObject, connectGetter);
1480 descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
1484 if (propertyName == Identifier(exec, "disconnect")) {
1486 slot.setCustom(thisObject, disconnectGetter);
1487 descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
1491 if (propertyName == exec->propertyNames().length) {
1493 slot.setCustom(thisObject, lengthGetter);
1494 descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
1498 return QtRuntimeMethod::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
1501 void QtRuntimeMetaMethod::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
1503 if (mode == IncludeDontEnumProperties) {
1504 propertyNames.add(Identifier(exec, "connect"));
1505 propertyNames.add(Identifier(exec, "disconnect"));
1506 propertyNames.add(exec->propertyNames().length);
1509 QtRuntimeMethod::getOwnPropertyNames(object, exec, propertyNames, mode);
1512 JSValue QtRuntimeMetaMethod::lengthGetter(ExecState*, JSValue, PropertyName)
1514 // QtScript always returns 0
1518 JSValue QtRuntimeMetaMethod::connectGetter(ExecState* exec, JSValue slotBase, PropertyName ident)
1520 QtRuntimeMetaMethod* thisObj = static_cast<QtRuntimeMetaMethod*>(asObject(slotBase));
1521 QW_DS(QtRuntimeMetaMethod, thisObj);
1524 d->m_connect.set(exec->globalData(), thisObj, QtRuntimeConnectionMethod::create(exec, ident.publicName(), true, d->m_instance, d->m_index, d->m_signature));
1525 return d->m_connect.get();
1528 JSValue QtRuntimeMetaMethod::disconnectGetter(ExecState* exec, JSValue slotBase, PropertyName ident)
1530 QtRuntimeMetaMethod* thisObj = static_cast<QtRuntimeMetaMethod*>(asObject(slotBase));
1531 QW_DS(QtRuntimeMetaMethod, thisObj);
1533 if (!d->m_disconnect)
1534 d->m_disconnect.set(exec->globalData(), thisObj, QtRuntimeConnectionMethod::create(exec, ident.publicName(), false, d->m_instance, d->m_index, d->m_signature));
1535 return d->m_disconnect.get();
1540 QMultiMap<QObject*, QtConnectionObject*> QtRuntimeConnectionMethod::connections;
1542 const ClassInfo QtRuntimeConnectionMethod::s_info = { "QtRuntimeMethod", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(QtRuntimeConnectionMethod) };
1544 QtRuntimeConnectionMethod::QtRuntimeConnectionMethod(ExecState* exec, Structure* structure, const UString& identifier)
1545 : QtRuntimeMethod (new QtRuntimeConnectionMethodData(), exec, structure, identifier)
1549 void QtRuntimeConnectionMethod::finishCreation(ExecState* exec, const UString& identifier, bool isConnect, PassRefPtr<QtInstance> instance, int index, const QByteArray& signature)
1551 Base::finishCreation(exec, identifier, instance);
1552 QW_D(QtRuntimeConnectionMethod);
1554 d->m_signature = signature;
1556 d->m_isConnect = isConnect;
1559 EncodedJSValue QtRuntimeConnectionMethod::call(ExecState* exec)
1561 QtRuntimeConnectionMethodData* d = static_cast<QtRuntimeConnectionMethod *>(exec->callee())->d_func();
1563 JSLock lock(SilenceAssertionsOnly);
1565 QObject* sender = d->m_instance->getObject();
1569 JSObject* thisObject = exec->lexicalGlobalObject()->methodTable()->toThisObject(exec->lexicalGlobalObject(), exec);
1570 JSObject* funcObject = 0;
1572 // QtScript checks signalness first, arguments second
1573 int signalIndex = -1;
1575 // Make sure the initial index is a signal
1576 QMetaMethod m = sender->metaObject()->method(d->m_index);
1577 if (m.methodType() == QMetaMethod::Signal)
1578 signalIndex = findSignalIndex(sender->metaObject(), d->m_index, d->m_signature);
1580 if (signalIndex != -1) {
1581 if (exec->argumentCount() == 1) {
1582 funcObject = exec->argument(0).toObject(exec);
1584 if (funcObject->methodTable()->getCallData(funcObject, callData) == CallTypeNone) {
1586 return throwVMError(exec, createTypeError(exec, "QtMetaMethod.connect: target is not a function"));
1588 return throwVMError(exec, createTypeError(exec, "QtMetaMethod.disconnect: target is not a function"));
1590 } else if (exec->argumentCount() >= 2) {
1591 if (exec->argument(0).isObject()) {
1592 thisObject = exec->argument(0).toObject(exec);
1594 // Get the actual function to call
1595 JSObject *asObj = exec->argument(1).toObject(exec);
1597 if (asObj->methodTable()->getCallData(asObj, callData) != CallTypeNone) {
1601 // Convert it to a string
1602 UString funcName = exec->argument(1).toString(exec)->value(exec);
1603 Identifier funcIdent(exec, funcName);
1606 // This is resolved at this point in QtScript
1607 JSValue val = thisObject->get(exec, funcIdent);
1608 JSObject* asFuncObj = val.toObject(exec);
1610 if (asFuncObj->methodTable()->getCallData(asFuncObj, callData) != CallTypeNone) {
1611 funcObject = asFuncObj;
1614 return throwVMError(exec, createTypeError(exec, "QtMetaMethod.connect: target is not a function"));
1616 return throwVMError(exec, createTypeError(exec, "QtMetaMethod.disconnect: target is not a function"));
1621 return throwVMError(exec, createTypeError(exec, "QtMetaMethod.connect: thisObject is not an object"));
1623 return throwVMError(exec, createTypeError(exec, "QtMetaMethod.disconnect: thisObject is not an object"));
1627 return throwVMError(exec, createError(exec, "QtMetaMethod.connect: no arguments given"));
1629 return throwVMError(exec, createError(exec, "QtMetaMethod.disconnect: no arguments given"));
1632 if (d->m_isConnect) {
1633 // to connect, we need:
1634 // target object [from ctor]
1635 // target signal index etc. [from ctor]
1636 // receiver function [from arguments]
1637 // receiver this object [from arguments]
1639 ExecState* globalExec = exec->lexicalGlobalObject()->globalExec();
1640 QtConnectionObject* conn = QtConnectionObject::createWithInternalJSC(globalExec, d->m_instance, signalIndex, thisObject, funcObject);
1641 bool ok = QMetaObject::connect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
1644 QString msg = QString(QLatin1String("QtMetaMethod.connect: failed to connect to %1::%2()"))
1645 .arg(QLatin1String(sender->metaObject()->className()))
1646 .arg(QLatin1String(d->m_signature));
1647 return throwVMError(exec, createError(exec, msg.toLatin1().constData()));
1651 connections.insert(sender, conn);
1654 // Now to find our previous connection object. Hmm.
1655 QList<QtConnectionObject*> conns = connections.values(sender);
1658 JSContextRef context = ::toRef(exec);
1659 JSObjectRef receiver = ::toRef(thisObject);
1660 JSObjectRef receiverFunction = ::toRef(funcObject);
1662 foreach(QtConnectionObject* conn, conns) {
1663 // Is this the right connection?
1664 if (conn->match(context, sender, signalIndex, receiver, receiverFunction)) {
1665 // Yep, disconnect it
1666 QMetaObject::disconnect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
1667 delete conn; // this will also remove it from the map
1674 QString msg = QString(QLatin1String("QtMetaMethod.disconnect: failed to disconnect from %1::%2()"))
1675 .arg(QLatin1String(sender->metaObject()->className()))
1676 .arg(QLatin1String(d->m_signature));
1677 return throwVMError(exec, createError(exec, msg.toLatin1().constData()));
1681 QString msg = QString(QLatin1String("QtMetaMethod.%1: %2::%3() is not a signal"))
1682 .arg(QLatin1String(d->m_isConnect ? "connect": "disconnect"))
1683 .arg(QLatin1String(sender->metaObject()->className()))
1684 .arg(QLatin1String(d->m_signature));
1685 return throwVMError(exec, createTypeError(exec, msg.toLatin1().constData()));
1688 return throwVMError(exec, createError(exec, "cannot call function of deleted QObject"));
1691 return JSValue::encode(jsUndefined());
1694 CallType QtRuntimeConnectionMethod::getCallData(JSCell*, CallData& callData)
1696 callData.native.function = call;
1697 return CallTypeHost;
1700 bool QtRuntimeConnectionMethod::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
1702 QtRuntimeConnectionMethod* thisObject = jsCast<QtRuntimeConnectionMethod*>(cell);
1703 if (propertyName == exec->propertyNames().length) {
1704 slot.setCustom(thisObject, thisObject->lengthGetter);
1708 return QtRuntimeMethod::getOwnPropertySlot(thisObject, exec, propertyName, slot);
1711 bool QtRuntimeConnectionMethod::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
1713 QtRuntimeConnectionMethod* thisObject = jsCast<QtRuntimeConnectionMethod*>(object);
1714 if (propertyName == exec->propertyNames().length) {
1716 slot.setCustom(thisObject, lengthGetter);
1717 descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
1721 return QtRuntimeMethod::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
1724 void QtRuntimeConnectionMethod::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
1726 if (mode == IncludeDontEnumProperties)
1727 propertyNames.add(exec->propertyNames().length);
1729 QtRuntimeMethod::getOwnPropertyNames(object, exec, propertyNames, mode);
1732 JSValue QtRuntimeConnectionMethod::lengthGetter(ExecState*, JSValue, PropertyName)
1734 // we have one formal argument, and one optional
1740 QtConnectionObject::QtConnectionObject(JSContextRef context, PassRefPtr<QtInstance> senderInstance, int signalIndex, JSObjectRef receiver, JSObjectRef receiverFunction)
1741 : QObject(senderInstance->getObject())
1742 , m_context(context)
1743 , m_senderInstance(senderInstance)
1744 , m_originalSender(m_senderInstance->getObject())
1745 , m_signalIndex(signalIndex)
1746 , m_receiver(receiver)
1747 , m_receiverFunction(receiverFunction)
1749 JSValueProtect(m_context, m_receiver);
1750 JSValueProtect(m_context, m_receiverFunction);
1753 QtConnectionObject::~QtConnectionObject()
1755 // We can safely use m_originalSender because connection object will never outlive the sender,
1756 // which is its QObject parent.
1757 QtRuntimeConnectionMethod::connections.remove(m_originalSender, this);
1759 JSValueUnprotect(m_context, m_receiver);
1760 JSValueUnprotect(m_context, m_receiverFunction);
1763 // Begin moc-generated code -- modify with care! Check "HAND EDIT" parts
1764 struct qt_meta_stringdata_QtConnectionObject_t {
1765 QByteArrayData data[3];
1766 char stringdata[44];
1768 #define QT_MOC_LITERAL(idx, ofs, len) { \
1769 Q_REFCOUNT_INITIALIZE_STATIC, len, 0, 0, \
1770 offsetof(qt_meta_stringdata_QtConnectionObject_t, stringdata) + ofs \
1771 - idx * sizeof(QByteArrayData) \
1773 static const qt_meta_stringdata_QtConnectionObject_t qt_meta_stringdata_QtConnectionObject = {
1775 QT_MOC_LITERAL(0, 0, 33),
1776 QT_MOC_LITERAL(1, 34, 7),
1777 QT_MOC_LITERAL(2, 42, 0)
1779 "JSC::Bindings::QtConnectionObject\0"
1782 #undef QT_MOC_LITERAL
1784 static const uint qt_meta_data_QtConnectionObject[] = {
1793 0, 0, // constructors
1797 // slots: name, argc, parameters, tag, flags
1800 // slots: parameters
1806 void QtConnectionObject::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
1808 if (_c == QMetaObject::InvokeMetaMethod) {
1809 Q_ASSERT(staticMetaObject.cast(_o));
1810 QtConnectionObject *_t = static_cast<QtConnectionObject *>(_o);
1812 case 0: _t->execute(_a); break; // HAND EDIT: add _a parameter
1818 const QMetaObject QtConnectionObject::staticMetaObject = {
1819 { &QObject::staticMetaObject, qt_meta_stringdata_QtConnectionObject.data,
1820 qt_meta_data_QtConnectionObject, qt_static_metacall, 0, 0 }
1823 const QMetaObject *QtConnectionObject::metaObject() const
1825 return &staticMetaObject;
1828 void *QtConnectionObject::qt_metacast(const char *_clname)
1830 if (!_clname) return 0;
1831 if (!strcmp(_clname, qt_meta_stringdata_QtConnectionObject.stringdata))
1832 return static_cast<void*>(const_cast<QtConnectionObject*>(this));
1833 return QObject::qt_metacast(_clname);
1836 int QtConnectionObject::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
1838 _id = QObject::qt_metacall(_c, _id, _a);
1841 if (_c == QMetaObject::InvokeMetaMethod) {
1843 qt_static_metacall(this, _c, _id, _a);
1848 // End of moc-generated code
1850 static bool isJavaScriptFunction(JSObjectRef object)
1853 JSObject* jsObject = toJS(object);
1854 return jsObject->methodTable()->getCallData(jsObject, callData) == CallTypeJS;
1857 void QtConnectionObject::execute(void** argv)
1859 QObject* sender = m_senderInstance->getObject();
1861 qWarning() << "sender deleted, cannot deliver signal";
1865 ASSERT(sender == m_originalSender);
1867 const QMetaObject* meta = sender->metaObject();
1868 const QMetaMethod method = meta->method(m_signalIndex);
1870 JSValueRef* ignoredException = 0;
1871 JSRetainPtr<JSStringRef> lengthProperty(JSStringCreateWithUTF8CString("length"));
1872 int receiverLength = int(JSValueToNumber(m_context, JSObjectGetProperty(m_context, m_receiverFunction, lengthProperty.get(), ignoredException), ignoredException));
1873 int argc = qMax(method.parameterCount(), receiverLength);
1874 WTF::Vector<JSValueRef> args(argc);
1876 // TODO: remove once conversion functions use JSC API.
1877 ExecState* exec = ::toJS(m_context);
1878 RefPtr<RootObject> rootObject = m_senderInstance->rootObject();
1880 for (int i = 0; i < argc; i++) {
1881 int argType = method.parameterType(i);
1882 args[i] = ::toRef(exec, convertQVariantToValue(exec, rootObject, QVariant(argType, argv[i+1])));
1885 const bool updateQtSender = isJavaScriptFunction(m_receiverFunction);
1887 QtInstance::qtSenderStack()->push(QObject::sender());
1889 JSObjectCallAsFunction(m_context, m_receiverFunction, m_receiver, argc, args.data(), 0);
1892 QtInstance::qtSenderStack()->pop();
1895 bool QtConnectionObject::match(JSContextRef context, QObject* sender, int signalIndex, JSObjectRef receiver, JSObjectRef receiverFunction)
1897 if (sender != m_originalSender || signalIndex != m_signalIndex)
1899 JSValueRef* ignoredException = 0;
1900 const bool receiverMatch = (!receiver && !m_receiver) || JSValueIsEqual(context, receiver, m_receiver, ignoredException);
1901 return receiverMatch && JSValueIsEqual(context, receiverFunction, m_receiverFunction, ignoredException);
1904 QtConnectionObject* QtConnectionObject::createWithInternalJSC(ExecState* exec, PassRefPtr<QtInstance> senderInstance, int signalIndex, JSObject* receiver, JSObject* receiverFunction)
1906 return new QtConnectionObject(::toRef(exec), senderInstance, signalIndex, ::toRef(receiver), ::toRef(receiverFunction));
1911 template <typename T> QtArray<T>::QtArray(QList<T> list, QMetaType::Type type, PassRefPtr<RootObject> rootObject)
1916 m_length = m_list.count();
1919 template <typename T> QtArray<T>::~QtArray ()
1923 template <typename T> RootObject* QtArray<T>::rootObject() const
1925 return m_rootObject && m_rootObject->isValid() ? m_rootObject.get() : 0;
1928 template <typename T> void QtArray<T>::setValueAt(ExecState* exec, unsigned index, JSValue aValue) const
1930 // QtScript sets the value, but doesn't forward it to the original source
1931 // (e.g. if you do 'object.intList[5] = 6', the object is not updated, but the
1932 // copy of the list is).
1934 QVariant val = convertValueToQVariant(exec, aValue, m_type, &dist);
1937 m_list[index] = val.value<T>();
1942 template <typename T> JSValue QtArray<T>::valueAt(ExecState *exec, unsigned int index) const
1944 if (index < m_length) {
1945 T val = m_list.at(index);
1946 return convertQVariantToValue(exec, rootObject(), QVariant::fromValue(val));
1949 return jsUndefined();