| Index: third_party/WebKit/WebCore/bridge/qt/qt_runtime.cpp
|
| ===================================================================
|
| --- third_party/WebKit/WebCore/bridge/qt/qt_runtime.cpp (revision 9383)
|
| +++ third_party/WebKit/WebCore/bridge/qt/qt_runtime.cpp (working copy)
|
| @@ -1,1773 +1,1773 @@
|
| -/*
|
| - * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
|
| - *
|
| - * This library is free software; you can redistribute it and/or
|
| - * modify it under the terms of the GNU Lesser General Public
|
| - * License as published by the Free Software Foundation; either
|
| - * version 2 of the License, or (at your option) any later version.
|
| - *
|
| - * This library is distributed in the hope that it will be useful,
|
| - * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| - * Lesser General Public License for more details.
|
| - *
|
| - * You should have received a copy of the GNU Lesser General Public
|
| - * License along with this library; if not, write to the Free Software
|
| - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| - *
|
| - */
|
| -
|
| -#include "config.h"
|
| -#include "qt_runtime.h"
|
| -
|
| -#include "DateInstance.h"
|
| -#include "DateMath.h"
|
| -#include "DatePrototype.h"
|
| -#include "FunctionPrototype.h"
|
| -#include "Interpreter.h"
|
| -#include "JSArray.h"
|
| -#include "JSByteArray.h"
|
| -#include "JSDOMBinding.h"
|
| -#include "JSGlobalObject.h"
|
| -#include "JSLock.h"
|
| -#include "JSObject.h"
|
| -#include "ObjectPrototype.h"
|
| -#include "PropertyNameArray.h"
|
| -#include "RegExpConstructor.h"
|
| -#include "RegExpObject.h"
|
| -#include "qdatetime.h"
|
| -#include "qdebug.h"
|
| -#include "qmetaobject.h"
|
| -#include "qmetatype.h"
|
| -#include "qobject.h"
|
| -#include "qstringlist.h"
|
| -#include "qt_instance.h"
|
| -#include "qvarlengtharray.h"
|
| -#include <JSFunction.h>
|
| -#include <limits.h>
|
| -#include <runtime.h>
|
| -#include <runtime_array.h>
|
| -#include <runtime_object.h>
|
| -#include "BooleanObject.h"
|
| -
|
| -// QtScript has these
|
| -Q_DECLARE_METATYPE(QObjectList);
|
| -Q_DECLARE_METATYPE(QList<int>);
|
| -Q_DECLARE_METATYPE(QVariant);
|
| -
|
| -using namespace WebCore;
|
| -
|
| -namespace JSC {
|
| -namespace Bindings {
|
| -
|
| -// Debugging
|
| -//#define QTWK_RUNTIME_CONVERSION_DEBUG
|
| -//#define QTWK_RUNTIME_MATCH_DEBUG
|
| -
|
| -class QWKNoDebug
|
| -{
|
| -public:
|
| - inline QWKNoDebug(){}
|
| - inline ~QWKNoDebug(){}
|
| -
|
| - template<typename T>
|
| - inline QWKNoDebug &operator<<(const T &) { return *this; }
|
| -};
|
| -
|
| -#ifdef QTWK_RUNTIME_CONVERSION_DEBUG
|
| -#define qConvDebug() qDebug()
|
| -#else
|
| -#define qConvDebug() QWKNoDebug()
|
| -#endif
|
| -
|
| -#ifdef QTWK_RUNTIME_MATCH_DEBUG
|
| -#define qMatchDebug() qDebug()
|
| -#else
|
| -#define qMatchDebug() QWKNoDebug()
|
| -#endif
|
| -
|
| -typedef enum {
|
| - Variant = 0,
|
| - Number,
|
| - Boolean,
|
| - String,
|
| - Date,
|
| - RegExp,
|
| - Array,
|
| - QObj,
|
| - Object,
|
| - Null,
|
| - RTArray,
|
| - JSByteArray
|
| -} JSRealType;
|
| -
|
| -#if defined(QTWK_RUNTIME_CONVERSION_DEBUG) || defined(QTWK_RUNTIME_MATCH_DEBUG)
|
| -QDebug operator<<(QDebug dbg, const JSRealType &c)
|
| -{
|
| - const char *map[] = { "Variant", "Number", "Boolean", "String", "Date",
|
| - "RegExp", "Array", "RTObject", "Object", "Null", "RTArray"};
|
| -
|
| - dbg.nospace() << "JSType(" << ((int)c) << ", " << map[c] << ")";
|
| -
|
| - return dbg.space();
|
| -}
|
| -#endif
|
| -
|
| -static JSRealType valueRealType(ExecState* exec, JSValuePtr val)
|
| -{
|
| - if (val.isNumber())
|
| - return Number;
|
| - else if (val.isString())
|
| - return String;
|
| - else if (val.isBoolean())
|
| - return Boolean;
|
| - else if (val.isNull())
|
| - return Null;
|
| - else if (exec->interpreter()->isJSByteArray(val))
|
| - return JSByteArray;
|
| - else if (val.isObject()) {
|
| - JSObject *object = val.toObject(exec);
|
| - if (object->inherits(&RuntimeArray::s_info)) // RuntimeArray 'inherits' from Array, but not in C++
|
| - return RTArray;
|
| - else if (object->inherits(&JSArray::info))
|
| - return Array;
|
| - else if (object->inherits(&DateInstance::info))
|
| - return Date;
|
| - else if (object->inherits(&RegExpObject::info))
|
| - return RegExp;
|
| - else if (object->inherits(&RuntimeObjectImp::s_info))
|
| - return QObj;
|
| - return Object;
|
| - }
|
| -
|
| - return String; // I don't know.
|
| -}
|
| -
|
| -QVariant convertValueToQVariant(ExecState* exec, JSValuePtr value, QMetaType::Type hint, int *distance, HashSet<JSObject*>* visitedObjects)
|
| -{
|
| - JSObject* object = 0;
|
| - if (value.isObject()) {
|
| - object = value.toObject(exec);
|
| - if (visitedObjects->contains(object))
|
| - return QVariant();
|
| -
|
| - visitedObjects->add(object);
|
| - }
|
| -
|
| - // check magic pointer values before dereferencing value
|
| - if (value == jsNaN(exec)
|
| - || (value == jsUndefined()
|
| - && hint != QMetaType::QString
|
| - && hint != (QMetaType::Type) qMetaTypeId<QVariant>())) {
|
| - if (distance)
|
| - *distance = -1;
|
| - return QVariant();
|
| - }
|
| -
|
| - JSLock lock(false);
|
| - JSRealType type = valueRealType(exec, value);
|
| - if (hint == QMetaType::Void) {
|
| - switch(type) {
|
| - case Number:
|
| - hint = QMetaType::Double;
|
| - break;
|
| - case Boolean:
|
| - hint = QMetaType::Bool;
|
| - break;
|
| - case String:
|
| - default:
|
| - hint = QMetaType::QString;
|
| - break;
|
| - case Date:
|
| - hint = QMetaType::QDateTime;
|
| - break;
|
| - case RegExp:
|
| - hint = QMetaType::QRegExp;
|
| - break;
|
| - case Object:
|
| - if (object->inherits(&NumberObject::info))
|
| - hint = QMetaType::Double;
|
| - else if (object->inherits(&BooleanObject::info))
|
| - hint = QMetaType::Bool;
|
| - else
|
| - hint = QMetaType::QVariantMap;
|
| - break;
|
| - case QObj:
|
| - hint = QMetaType::QObjectStar;
|
| - break;
|
| - case JSByteArray:
|
| - hint = QMetaType::QByteArray;
|
| - break;
|
| - case Array:
|
| - case RTArray:
|
| - hint = QMetaType::QVariantList;
|
| - break;
|
| - }
|
| - }
|
| -
|
| - qConvDebug() << "convertValueToQVariant: jstype is " << type << ", hint is" << hint;
|
| -
|
| - if (value == jsNull()
|
| - && hint != QMetaType::QObjectStar
|
| - && hint != QMetaType::VoidStar
|
| - && hint != QMetaType::QString
|
| - && hint != (QMetaType::Type) qMetaTypeId<QVariant>()) {
|
| - if (distance)
|
| - *distance = -1;
|
| - return QVariant();
|
| - }
|
| -
|
| - QVariant ret;
|
| - int dist = -1;
|
| - switch (hint) {
|
| - case QMetaType::Bool:
|
| - if (type == Object && object->inherits(&BooleanObject::info))
|
| - ret = QVariant(asBooleanObject(value)->internalValue().toBoolean(exec));
|
| - else
|
| - ret = QVariant(value.toBoolean(exec));
|
| - if (type == Boolean)
|
| - dist = 0;
|
| - else
|
| - dist = 10;
|
| - break;
|
| -
|
| - case QMetaType::Int:
|
| - case QMetaType::UInt:
|
| - case QMetaType::Long:
|
| - case QMetaType::ULong:
|
| - case QMetaType::LongLong:
|
| - case QMetaType::ULongLong:
|
| - case QMetaType::Short:
|
| - case QMetaType::UShort:
|
| - case QMetaType::Float:
|
| - case QMetaType::Double:
|
| - ret = QVariant(value.toNumber(exec));
|
| - ret.convert((QVariant::Type)hint);
|
| - if (type == Number) {
|
| - switch (hint) {
|
| - case QMetaType::Double:
|
| - dist = 0;
|
| - break;
|
| - case QMetaType::Float:
|
| - dist = 1;
|
| - break;
|
| - case QMetaType::LongLong:
|
| - case QMetaType::ULongLong:
|
| - dist = 2;
|
| - break;
|
| - case QMetaType::Long:
|
| - case QMetaType::ULong:
|
| - dist = 3;
|
| - break;
|
| - case QMetaType::Int:
|
| - case QMetaType::UInt:
|
| - dist = 4;
|
| - break;
|
| - case QMetaType::Short:
|
| - case QMetaType::UShort:
|
| - dist = 5;
|
| - break;
|
| - break;
|
| - default:
|
| - dist = 10;
|
| - break;
|
| - }
|
| - } else {
|
| - dist = 10;
|
| - }
|
| - break;
|
| -
|
| - case QMetaType::QChar:
|
| - if (type == Number || type == Boolean) {
|
| - ret = QVariant(QChar((ushort)value.toNumber(exec)));
|
| - if (type == Boolean)
|
| - dist = 3;
|
| - else
|
| - dist = 6;
|
| - } else {
|
| - UString str = value.toString(exec);
|
| - ret = QVariant(QChar(str.size() ? *(const ushort*)str.rep()->data() : 0));
|
| - if (type == String)
|
| - dist = 3;
|
| - else
|
| - dist = 10;
|
| - }
|
| - break;
|
| -
|
| - case QMetaType::QString: {
|
| - if (value.isUndefinedOrNull()) {
|
| - if (distance)
|
| - *distance = 1;
|
| - return QString();
|
| - } else {
|
| - UString ustring = value.toString(exec);
|
| - ret = QVariant(QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size()));
|
| - if (type == String)
|
| - dist = 0;
|
| - else
|
| - dist = 10;
|
| - }
|
| - break;
|
| - }
|
| -
|
| - case QMetaType::QVariantMap:
|
| - if (type == Object || type == Array || type == RTArray) {
|
| - // Enumerate the contents of the object
|
| - PropertyNameArray properties(exec);
|
| - object->getPropertyNames(exec, properties);
|
| - PropertyNameArray::const_iterator it = properties.begin();
|
| -
|
| - QVariantMap result;
|
| - int objdist = 0;
|
| - while(it != properties.end()) {
|
| - if (object->propertyIsEnumerable(exec, *it)) {
|
| - JSValuePtr val = object->get(exec, *it);
|
| - QVariant v = convertValueToQVariant(exec, val, QMetaType::Void, &objdist, visitedObjects);
|
| - if (objdist >= 0) {
|
| - UString ustring = (*it).ustring();
|
| - QString id = QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size());
|
| - result.insert(id, v);
|
| - }
|
| - }
|
| - ++it;
|
| - }
|
| - dist = 1;
|
| - ret = QVariant(result);
|
| - }
|
| - break;
|
| -
|
| - case QMetaType::QVariantList:
|
| - if (type == RTArray) {
|
| - RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
|
| -
|
| - QVariantList result;
|
| - int len = rtarray->getLength();
|
| - int objdist = 0;
|
| - qConvDebug() << "converting a " << len << " length Array";
|
| - for (int i = 0; i < len; ++i) {
|
| - JSValuePtr val = rtarray->getConcreteArray()->valueAt(exec, i);
|
| - result.append(convertValueToQVariant(exec, val, QMetaType::Void, &objdist, visitedObjects));
|
| - if (objdist == -1) {
|
| - qConvDebug() << "Failed converting element at index " << i;
|
| - break; // Failed converting a list entry, so fail the array
|
| - }
|
| - }
|
| - if (objdist != -1) {
|
| - dist = 5;
|
| - ret = QVariant(result);
|
| - }
|
| - } else if (type == Array) {
|
| - JSArray* array = static_cast<JSArray*>(object);
|
| -
|
| - QVariantList result;
|
| - int len = array->length();
|
| - int objdist = 0;
|
| - qConvDebug() << "converting a " << len << " length Array";
|
| - for (int i = 0; i < len; ++i) {
|
| - JSValuePtr val = array->get(exec, i);
|
| - result.append(convertValueToQVariant(exec, val, QMetaType::Void, &objdist, visitedObjects));
|
| - if (objdist == -1) {
|
| - qConvDebug() << "Failed converting element at index " << i;
|
| - break; // Failed converting a list entry, so fail the array
|
| - }
|
| - }
|
| - if (objdist != -1) {
|
| - dist = 5;
|
| - ret = QVariant(result);
|
| - }
|
| - } else {
|
| - // Make a single length array
|
| - int objdist;
|
| - qConvDebug() << "making a single length variantlist";
|
| - QVariant var = convertValueToQVariant(exec, value, QMetaType::Void, &objdist, visitedObjects);
|
| - if (objdist != -1) {
|
| - QVariantList result;
|
| - result << var;
|
| - ret = QVariant(result);
|
| - dist = 10;
|
| - } else {
|
| - qConvDebug() << "failed making single length varlist";
|
| - }
|
| - }
|
| - break;
|
| -
|
| - case QMetaType::QStringList: {
|
| - if (type == RTArray) {
|
| - RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
|
| -
|
| - QStringList result;
|
| - int len = rtarray->getLength();
|
| - for (int i = 0; i < len; ++i) {
|
| - JSValuePtr val = rtarray->getConcreteArray()->valueAt(exec, i);
|
| - UString ustring = val.toString(exec);
|
| - QString qstring = QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size());
|
| -
|
| - result.append(qstring);
|
| - }
|
| - dist = 5;
|
| - ret = QVariant(result);
|
| - } else if (type == Array) {
|
| - JSArray* array = static_cast<JSArray*>(object);
|
| -
|
| - QStringList result;
|
| - int len = array->length();
|
| - for (int i = 0; i < len; ++i) {
|
| - JSValuePtr val = array->get(exec, i);
|
| - UString ustring = val.toString(exec);
|
| - QString qstring = QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size());
|
| -
|
| - result.append(qstring);
|
| - }
|
| - dist = 5;
|
| - ret = QVariant(result);
|
| - } else {
|
| - // Make a single length array
|
| - UString ustring = value.toString(exec);
|
| - QString qstring = QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size());
|
| - QStringList result;
|
| - result.append(qstring);
|
| - ret = QVariant(result);
|
| - dist = 10;
|
| - }
|
| - break;
|
| - }
|
| -
|
| - case QMetaType::QByteArray: {
|
| - if (type == JSByteArray) {
|
| - WTF::ByteArray* arr = asByteArray(value)->storage();
|
| - ret = QVariant(QByteArray(reinterpret_cast<const char*>(arr->data()), arr->length()));
|
| - dist = 0;
|
| - } else {
|
| - UString ustring = value.toString(exec);
|
| - ret = QVariant(QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size()).toLatin1());
|
| - if (type == String)
|
| - dist = 5;
|
| - else
|
| - dist = 10;
|
| - }
|
| - break;
|
| - }
|
| -
|
| - case QMetaType::QDateTime:
|
| - case QMetaType::QDate:
|
| - case QMetaType::QTime:
|
| - if (type == Date) {
|
| - DateInstance* date = static_cast<DateInstance*>(object);
|
| - GregorianDateTime gdt;
|
| - date->getUTCTime(gdt);
|
| - if (hint == QMetaType::QDateTime) {
|
| - ret = QDateTime(QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay), QTime(gdt.hour, gdt.minute, gdt.second), Qt::UTC);
|
| - dist = 0;
|
| - } else if (hint == QMetaType::QDate) {
|
| - ret = QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay);
|
| - dist = 1;
|
| - } else {
|
| - ret = QTime(gdt.hour + 1900, gdt.minute, gdt.second);
|
| - dist = 2;
|
| - }
|
| - } else if (type == Number) {
|
| - double b = value.toNumber(exec);
|
| - GregorianDateTime gdt;
|
| - msToGregorianDateTime(b, true, gdt);
|
| - if (hint == QMetaType::QDateTime) {
|
| - ret = QDateTime(QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay), QTime(gdt.hour, gdt.minute, gdt.second), Qt::UTC);
|
| - dist = 6;
|
| - } else if (hint == QMetaType::QDate) {
|
| - ret = QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay);
|
| - dist = 8;
|
| - } else {
|
| - ret = QTime(gdt.hour, gdt.minute, gdt.second);
|
| - dist = 10;
|
| - }
|
| - } else if (type == String) {
|
| - UString ustring = value.toString(exec);
|
| - QString qstring = QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size());
|
| -
|
| - if (hint == QMetaType::QDateTime) {
|
| - QDateTime dt = QDateTime::fromString(qstring, Qt::ISODate);
|
| - if (!dt.isValid())
|
| - dt = QDateTime::fromString(qstring, Qt::TextDate);
|
| - if (!dt.isValid())
|
| - dt = QDateTime::fromString(qstring, Qt::SystemLocaleDate);
|
| - if (!dt.isValid())
|
| - dt = QDateTime::fromString(qstring, Qt::LocaleDate);
|
| - if (dt.isValid()) {
|
| - ret = dt;
|
| - dist = 2;
|
| - }
|
| - } else if (hint == QMetaType::QDate) {
|
| - QDate dt = QDate::fromString(qstring, Qt::ISODate);
|
| - if (!dt.isValid())
|
| - dt = QDate::fromString(qstring, Qt::TextDate);
|
| - if (!dt.isValid())
|
| - dt = QDate::fromString(qstring, Qt::SystemLocaleDate);
|
| - if (!dt.isValid())
|
| - dt = QDate::fromString(qstring, Qt::LocaleDate);
|
| - if (dt.isValid()) {
|
| - ret = dt;
|
| - dist = 3;
|
| - }
|
| - } else {
|
| - QTime dt = QTime::fromString(qstring, Qt::ISODate);
|
| - if (!dt.isValid())
|
| - dt = QTime::fromString(qstring, Qt::TextDate);
|
| - if (!dt.isValid())
|
| - dt = QTime::fromString(qstring, Qt::SystemLocaleDate);
|
| - if (!dt.isValid())
|
| - dt = QTime::fromString(qstring, Qt::LocaleDate);
|
| - if (dt.isValid()) {
|
| - ret = dt;
|
| - dist = 3;
|
| - }
|
| - }
|
| - }
|
| - break;
|
| -
|
| - case QMetaType::QRegExp:
|
| - if (type == RegExp) {
|
| -/*
|
| - RegExpObject *re = static_cast<RegExpObject*>(object);
|
| -*/
|
| - // Attempt to convert.. a bit risky
|
| - UString ustring = value.toString(exec);
|
| - QString qstring = QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size());
|
| -
|
| - // this is of the form '/xxxxxx/i'
|
| - int firstSlash = qstring.indexOf(QLatin1Char('/'));
|
| - int lastSlash = qstring.lastIndexOf(QLatin1Char('/'));
|
| - if (firstSlash >=0 && lastSlash > firstSlash) {
|
| - QRegExp realRe;
|
| -
|
| - realRe.setPattern(qstring.mid(firstSlash + 1, lastSlash - firstSlash - 1));
|
| -
|
| - if (qstring.mid(lastSlash + 1).contains(QLatin1Char('i')))
|
| - realRe.setCaseSensitivity(Qt::CaseInsensitive);
|
| -
|
| - ret = qVariantFromValue(realRe);
|
| - dist = 0;
|
| - } else {
|
| - qConvDebug() << "couldn't parse a JS regexp";
|
| - }
|
| - } else if (type == String) {
|
| - UString ustring = value.toString(exec);
|
| - QString qstring = QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size());
|
| -
|
| - QRegExp re(qstring);
|
| - if (re.isValid()) {
|
| - ret = qVariantFromValue(re);
|
| - dist = 10;
|
| - }
|
| - }
|
| - break;
|
| -
|
| - case QMetaType::QObjectStar:
|
| - if (type == QObj) {
|
| - QtInstance* qtinst = QtInstance::getInstance(object);
|
| - if (qtinst) {
|
| - if (qtinst->getObject()) {
|
| - qConvDebug() << "found instance, with object:" << (void*) qtinst->getObject();
|
| - ret = qVariantFromValue(qtinst->getObject());
|
| - qConvDebug() << ret;
|
| - dist = 0;
|
| - } else {
|
| - qConvDebug() << "can't convert deleted qobject";
|
| - }
|
| - } else {
|
| - qConvDebug() << "wasn't a qtinstance";
|
| - }
|
| - } else if (type == Null) {
|
| - QObject* nullobj = 0;
|
| - ret = qVariantFromValue(nullobj);
|
| - dist = 0;
|
| - } else {
|
| - qConvDebug() << "previous type was not an object:" << type;
|
| - }
|
| - break;
|
| -
|
| - case QMetaType::VoidStar:
|
| - if (type == QObj) {
|
| - QtInstance* qtinst = QtInstance::getInstance(object);
|
| - if (qtinst) {
|
| - if (qtinst->getObject()) {
|
| - qConvDebug() << "found instance, with object:" << (void*) qtinst->getObject();
|
| - ret = qVariantFromValue((void *)qtinst->getObject());
|
| - qConvDebug() << ret;
|
| - dist = 0;
|
| - } else {
|
| - qConvDebug() << "can't convert deleted qobject";
|
| - }
|
| - } else {
|
| - qConvDebug() << "wasn't a qtinstance";
|
| - }
|
| - } else if (type == Null) {
|
| - ret = qVariantFromValue((void*)0);
|
| - dist = 0;
|
| - } else if (type == Number) {
|
| - // I don't think that converting a double to a pointer is a wise
|
| - // move. Except maybe 0.
|
| - qConvDebug() << "got number for void * - not converting, seems unsafe:" << value.toNumber(exec);
|
| - } else {
|
| - qConvDebug() << "void* - unhandled type" << type;
|
| - }
|
| - break;
|
| -
|
| - default:
|
| - // Non const type ids
|
| - if (hint == (QMetaType::Type) qMetaTypeId<QObjectList>())
|
| - {
|
| - if (type == RTArray) {
|
| - RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
|
| -
|
| - QObjectList result;
|
| - int len = rtarray->getLength();
|
| - for (int i = 0; i < len; ++i) {
|
| - JSValuePtr val = rtarray->getConcreteArray()->valueAt(exec, i);
|
| - int itemdist = -1;
|
| - QVariant item = convertValueToQVariant(exec, val, QMetaType::QObjectStar, &itemdist, visitedObjects);
|
| - if (itemdist >= 0)
|
| - result.append(item.value<QObject*>());
|
| - else
|
| - break;
|
| - }
|
| - // If we didn't fail conversion
|
| - if (result.count() == len) {
|
| - dist = 5;
|
| - ret = QVariant::fromValue(result);
|
| - }
|
| - } else if (type == Array) {
|
| - JSObject* object = value.toObject(exec);
|
| - JSArray* array = static_cast<JSArray *>(object);
|
| - QObjectList result;
|
| - int len = array->length();
|
| - for (int i = 0; i < len; ++i) {
|
| - JSValuePtr val = array->get(exec, i);
|
| - int itemdist = -1;
|
| - QVariant item = convertValueToQVariant(exec, val, QMetaType::QObjectStar, &itemdist, visitedObjects);
|
| - if (itemdist >= 0)
|
| - result.append(item.value<QObject*>());
|
| - else
|
| - break;
|
| - }
|
| - // If we didn't fail conversion
|
| - if (result.count() == len) {
|
| - dist = 5;
|
| - ret = QVariant::fromValue(result);
|
| - }
|
| - } else {
|
| - // Make a single length array
|
| - QObjectList result;
|
| - int itemdist = -1;
|
| - QVariant item = convertValueToQVariant(exec, value, QMetaType::QObjectStar, &itemdist, visitedObjects);
|
| - if (itemdist >= 0) {
|
| - result.append(item.value<QObject*>());
|
| - dist = 10;
|
| - ret = QVariant::fromValue(result);
|
| - }
|
| - }
|
| - break;
|
| - } else if (hint == (QMetaType::Type) qMetaTypeId<QList<int> >()) {
|
| - if (type == RTArray) {
|
| - RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
|
| -
|
| - QList<int> result;
|
| - int len = rtarray->getLength();
|
| - for (int i = 0; i < len; ++i) {
|
| - JSValuePtr val = rtarray->getConcreteArray()->valueAt(exec, i);
|
| - int itemdist = -1;
|
| - QVariant item = convertValueToQVariant(exec, val, QMetaType::Int, &itemdist, visitedObjects);
|
| - if (itemdist >= 0)
|
| - result.append(item.value<int>());
|
| - else
|
| - break;
|
| - }
|
| - // If we didn't fail conversion
|
| - if (result.count() == len) {
|
| - dist = 5;
|
| - ret = QVariant::fromValue(result);
|
| - }
|
| - } else if (type == Array) {
|
| - JSArray* array = static_cast<JSArray *>(object);
|
| -
|
| - QList<int> result;
|
| - int len = array->length();
|
| - for (int i = 0; i < len; ++i) {
|
| - JSValuePtr val = array->get(exec, i);
|
| - int itemdist = -1;
|
| - QVariant item = convertValueToQVariant(exec, val, QMetaType::Int, &itemdist, visitedObjects);
|
| - if (itemdist >= 0)
|
| - result.append(item.value<int>());
|
| - else
|
| - break;
|
| - }
|
| - // If we didn't fail conversion
|
| - if (result.count() == len) {
|
| - dist = 5;
|
| - ret = QVariant::fromValue(result);
|
| - }
|
| - } else {
|
| - // Make a single length array
|
| - QList<int> result;
|
| - int itemdist = -1;
|
| - QVariant item = convertValueToQVariant(exec, value, QMetaType::Int, &itemdist, visitedObjects);
|
| - if (itemdist >= 0) {
|
| - result.append(item.value<int>());
|
| - dist = 10;
|
| - ret = QVariant::fromValue(result);
|
| - }
|
| - }
|
| - break;
|
| - } else if (hint == (QMetaType::Type) qMetaTypeId<QVariant>()) {
|
| - if (value.isUndefinedOrNull()) {
|
| - if (distance)
|
| - *distance = 1;
|
| - return QVariant();
|
| - } else {
|
| - if (type == Object) {
|
| - // Since we haven't really visited this object yet, we remove it
|
| - visitedObjects->remove(object);
|
| - }
|
| -
|
| - // And then recurse with the autodetect flag
|
| - ret = convertValueToQVariant(exec, value, QMetaType::Void, distance, visitedObjects);
|
| - dist = 10;
|
| - }
|
| - break;
|
| - }
|
| -
|
| - dist = 10;
|
| - break;
|
| - }
|
| -
|
| - if (!ret.isValid())
|
| - dist = -1;
|
| - if (distance)
|
| - *distance = dist;
|
| -
|
| - return ret;
|
| -}
|
| -
|
| -QVariant convertValueToQVariant(ExecState* exec, JSValuePtr value, QMetaType::Type hint, int *distance)
|
| -{
|
| - HashSet<JSObject*> visitedObjects;
|
| - return convertValueToQVariant(exec, value, hint, distance, &visitedObjects);
|
| -}
|
| -
|
| -JSValuePtr convertQVariantToValue(ExecState* exec, PassRefPtr<RootObject> root, const QVariant& variant)
|
| -{
|
| - // Variants with QObject * can be isNull but not a null pointer
|
| - // An empty QString variant is also null
|
| - QMetaType::Type type = (QMetaType::Type) variant.userType();
|
| -
|
| - qConvDebug() << "convertQVariantToValue: metatype:" << type << ", isnull: " << variant.isNull();
|
| - if (variant.isNull() &&
|
| - type != QMetaType::QObjectStar &&
|
| - type != QMetaType::VoidStar &&
|
| - type != QMetaType::QWidgetStar &&
|
| - type != QMetaType::QString) {
|
| - return jsNull();
|
| - }
|
| -
|
| - JSLock lock(false);
|
| -
|
| - if (type == QMetaType::Bool)
|
| - return jsBoolean(variant.toBool());
|
| -
|
| - if (type == QMetaType::Int ||
|
| - type == QMetaType::UInt ||
|
| - type == QMetaType::Long ||
|
| - type == QMetaType::ULong ||
|
| - type == QMetaType::LongLong ||
|
| - type == QMetaType::ULongLong ||
|
| - type == QMetaType::Short ||
|
| - type == QMetaType::UShort ||
|
| - type == QMetaType::Float ||
|
| - type == QMetaType::Double)
|
| - return jsNumber(exec, variant.toDouble());
|
| -
|
| - if (type == QMetaType::QRegExp) {
|
| - QRegExp re = variant.value<QRegExp>();
|
| -
|
| - if (re.isValid()) {
|
| - UString uflags;
|
| - if (re.caseSensitivity() == Qt::CaseInsensitive)
|
| - uflags = "i"; // ### Can't do g or m
|
| -
|
| - UString pattern((UChar*)re.pattern().utf16(), re.pattern().length());
|
| -
|
| - RefPtr<JSC::RegExp> regExp = JSC::RegExp::create(&exec->globalData(), pattern, uflags);
|
| - if (regExp->isValid())
|
| - return new (exec) RegExpObject(exec->lexicalGlobalObject()->regExpStructure(), regExp.release());
|
| - else
|
| - return jsNull();
|
| - }
|
| - }
|
| -
|
| - if (type == QMetaType::QDateTime ||
|
| - type == QMetaType::QDate ||
|
| - type == QMetaType::QTime) {
|
| -
|
| - QDate date = QDate::currentDate();
|
| - QTime time(0,0,0); // midnight
|
| -
|
| - if (type == QMetaType::QDate)
|
| - date = variant.value<QDate>();
|
| - else if (type == QMetaType::QTime)
|
| - time = variant.value<QTime>();
|
| - else {
|
| - QDateTime dt = variant.value<QDateTime>().toLocalTime();
|
| - date = dt.date();
|
| - time = dt.time();
|
| - }
|
| -
|
| - // Dates specified this way are in local time (we convert DateTimes above)
|
| - GregorianDateTime dt;
|
| - dt.year = date.year() - 1900;
|
| - dt.month = date.month() - 1;
|
| - dt.monthDay = date.day();
|
| - dt.hour = time.hour();
|
| - dt.minute = time.minute();
|
| - dt.second = time.second();
|
| - dt.isDST = -1;
|
| - double ms = JSC::gregorianDateTimeToMS(dt, time.msec(), /*inputIsUTC*/ false);
|
| -
|
| - DateInstance* instance = new (exec) DateInstance(exec->lexicalGlobalObject()->dateStructure());
|
| - instance->setInternalValue(jsNumber(exec, trunc(ms)));
|
| - return instance;
|
| - }
|
| -
|
| - if (type == QMetaType::QByteArray) {
|
| - QByteArray qtByteArray = variant.value<QByteArray>();
|
| - WTF::RefPtr<WTF::ByteArray> wtfByteArray = WTF::ByteArray::create(qtByteArray.length());
|
| - qMemCopy(wtfByteArray->data(), qtByteArray.constData(), qtByteArray.length());
|
| - return new (exec) JSC::JSByteArray(exec, JSC::JSByteArray::createStructure(jsNull()), wtfByteArray.get());
|
| - }
|
| -
|
| - if (type == QMetaType::QObjectStar || type == QMetaType::QWidgetStar) {
|
| - QObject* obj = variant.value<QObject*>();
|
| - return QtInstance::getQtInstance(obj, root, QScriptEngine::QtOwnership)->createRuntimeObject(exec);
|
| - }
|
| -
|
| - if (type == QMetaType::QVariantMap) {
|
| - // create a new object, and stuff properties into it
|
| - JSObject* ret = constructEmptyObject(exec);
|
| - QVariantMap map = variant.value<QVariantMap>();
|
| - QVariantMap::const_iterator i = map.constBegin();
|
| - while (i != map.constEnd()) {
|
| - QString s = i.key();
|
| - JSValuePtr val = convertQVariantToValue(exec, root, i.value());
|
| - if (val) {
|
| - PutPropertySlot slot;
|
| - ret->put(exec, Identifier(exec, (const UChar *)s.constData(), s.length()), val, slot);
|
| - // ### error case?
|
| - }
|
| - ++i;
|
| - }
|
| -
|
| - return ret;
|
| - }
|
| -
|
| - // List types
|
| - if (type == QMetaType::QVariantList) {
|
| - QVariantList vl = variant.toList();
|
| - qConvDebug() << "got a " << vl.count() << " length list:" << vl;
|
| - return new (exec) RuntimeArray(exec, new QtArray<QVariant>(vl, QMetaType::Void, root));
|
| - } else if (type == QMetaType::QStringList) {
|
| - QStringList sl = variant.value<QStringList>();
|
| - return new (exec) RuntimeArray(exec, new QtArray<QString>(sl, QMetaType::QString, root));
|
| - } else if (type == (QMetaType::Type) qMetaTypeId<QObjectList>()) {
|
| - QObjectList ol= variant.value<QObjectList>();
|
| - return new (exec) RuntimeArray(exec, new QtArray<QObject*>(ol, QMetaType::QObjectStar, root));
|
| - } else if (type == (QMetaType::Type)qMetaTypeId<QList<int> >()) {
|
| - QList<int> il= variant.value<QList<int> >();
|
| - return new (exec) RuntimeArray(exec, new QtArray<int>(il, QMetaType::Int, root));
|
| - }
|
| -
|
| - if (type == (QMetaType::Type)qMetaTypeId<QVariant>()) {
|
| - QVariant real = variant.value<QVariant>();
|
| - qConvDebug() << "real variant is:" << real;
|
| - return convertQVariantToValue(exec, root, real);
|
| - }
|
| -
|
| - qConvDebug() << "fallback path for" << variant << variant.userType();
|
| -
|
| - QString string = variant.toString();
|
| - UString ustring((UChar*)string.utf16(), string.length());
|
| - return jsString(exec, ustring);
|
| -}
|
| -
|
| -// ===============
|
| -
|
| -// Qt-like macros
|
| -#define QW_D(Class) Class##Data* d = d_func()
|
| -#define QW_DS(Class,Instance) Class##Data* d = Instance->d_func()
|
| -
|
| -const ClassInfo QtRuntimeMethod::s_info = { "QtRuntimeMethod", 0, 0, 0 };
|
| -
|
| -QtRuntimeMethod::QtRuntimeMethod(QtRuntimeMethodData* dd, ExecState* exec, const Identifier& ident, PassRefPtr<QtInstance> inst)
|
| - : InternalFunction(&exec->globalData(), getDOMStructure<QtRuntimeMethod>(exec), ident)
|
| - , d_ptr(dd)
|
| -{
|
| - QW_D(QtRuntimeMethod);
|
| - d->m_instance = inst;
|
| -}
|
| -
|
| -QtRuntimeMethod::~QtRuntimeMethod()
|
| -{
|
| - delete d_ptr;
|
| -}
|
| -
|
| -// ===============
|
| -
|
| -QtRuntimeMethodData::~QtRuntimeMethodData()
|
| -{
|
| -}
|
| -
|
| -QtRuntimeMetaMethodData::~QtRuntimeMetaMethodData()
|
| -{
|
| -
|
| -}
|
| -
|
| -QtRuntimeConnectionMethodData::~QtRuntimeConnectionMethodData()
|
| -{
|
| -
|
| -}
|
| -
|
| -// ===============
|
| -
|
| -// Type conversion metadata (from QtScript originally)
|
| -class QtMethodMatchType
|
| -{
|
| -public:
|
| - enum Kind {
|
| - Invalid,
|
| - Variant,
|
| - MetaType,
|
| - Unresolved,
|
| - MetaEnum
|
| - };
|
| -
|
| -
|
| - QtMethodMatchType()
|
| - : m_kind(Invalid) { }
|
| -
|
| - Kind kind() const
|
| - { return m_kind; }
|
| -
|
| - QMetaType::Type typeId() const;
|
| -
|
| - bool isValid() const
|
| - { return (m_kind != Invalid); }
|
| -
|
| - bool isVariant() const
|
| - { return (m_kind == Variant); }
|
| -
|
| - bool isMetaType() const
|
| - { return (m_kind == MetaType); }
|
| -
|
| - bool isUnresolved() const
|
| - { return (m_kind == Unresolved); }
|
| -
|
| - bool isMetaEnum() const
|
| - { return (m_kind == MetaEnum); }
|
| -
|
| - QByteArray name() const;
|
| -
|
| - int enumeratorIndex() const
|
| - { Q_ASSERT(isMetaEnum()); return m_typeId; }
|
| -
|
| - static QtMethodMatchType variant()
|
| - { return QtMethodMatchType(Variant); }
|
| -
|
| - static QtMethodMatchType metaType(int typeId, const QByteArray &name)
|
| - { return QtMethodMatchType(MetaType, typeId, name); }
|
| -
|
| - static QtMethodMatchType metaEnum(int enumIndex, const QByteArray &name)
|
| - { return QtMethodMatchType(MetaEnum, enumIndex, name); }
|
| -
|
| - static QtMethodMatchType unresolved(const QByteArray &name)
|
| - { return QtMethodMatchType(Unresolved, /*typeId=*/0, name); }
|
| -
|
| -private:
|
| - QtMethodMatchType(Kind kind, int typeId = 0, const QByteArray &name = QByteArray())
|
| - : m_kind(kind), m_typeId(typeId), m_name(name) { }
|
| -
|
| - Kind m_kind;
|
| - int m_typeId;
|
| - QByteArray m_name;
|
| -};
|
| -
|
| -QMetaType::Type QtMethodMatchType::typeId() const
|
| -{
|
| - if (isVariant())
|
| - return (QMetaType::Type) QMetaType::type("QVariant");
|
| - return (QMetaType::Type) (isMetaEnum() ? QMetaType::Int : m_typeId);
|
| -}
|
| -
|
| -QByteArray QtMethodMatchType::name() const
|
| -{
|
| - if (!m_name.isEmpty())
|
| - return m_name;
|
| - else if (m_kind == Variant)
|
| - return "QVariant";
|
| - return QByteArray();
|
| -}
|
| -
|
| -struct QtMethodMatchData
|
| -{
|
| - int matchDistance;
|
| - int index;
|
| - QVector<QtMethodMatchType> types;
|
| - QVarLengthArray<QVariant, 10> args;
|
| -
|
| - QtMethodMatchData(int dist, int idx, QVector<QtMethodMatchType> typs,
|
| - const QVarLengthArray<QVariant, 10> &as)
|
| - : matchDistance(dist), index(idx), types(typs), args(as) { }
|
| - QtMethodMatchData()
|
| - : index(-1) { }
|
| -
|
| - bool isValid() const
|
| - { return (index != -1); }
|
| -
|
| - int firstUnresolvedIndex() const
|
| - {
|
| - for (int i=0; i < types.count(); i++) {
|
| - if (types.at(i).isUnresolved())
|
| - return i;
|
| - }
|
| - return -1;
|
| - }
|
| -};
|
| -
|
| -static int indexOfMetaEnum(const QMetaObject *meta, const QByteArray &str)
|
| -{
|
| - QByteArray scope;
|
| - QByteArray name;
|
| - int scopeIdx = str.indexOf("::");
|
| - if (scopeIdx != -1) {
|
| - scope = str.left(scopeIdx);
|
| - name = str.mid(scopeIdx + 2);
|
| - } else {
|
| - name = str;
|
| - }
|
| - for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
|
| - QMetaEnum m = meta->enumerator(i);
|
| - if ((m.name() == name)/* && (scope.isEmpty() || (m.scope() == scope))*/)
|
| - return i;
|
| - }
|
| - return -1;
|
| -}
|
| -
|
| -// Helper function for resolving methods
|
| -// Largely based on code in QtScript for compatibility reasons
|
| -static int findMethodIndex(ExecState* exec,
|
| - const QMetaObject* meta,
|
| - const QByteArray& signature,
|
| - bool allowPrivate,
|
| - const ArgList& jsArgs,
|
| - QVarLengthArray<QVariant, 10> &vars,
|
| - void** vvars,
|
| - JSObject **pError)
|
| -{
|
| - QList<int> matchingIndices;
|
| -
|
| - bool overloads = !signature.contains('(');
|
| -
|
| - int count = meta->methodCount();
|
| - for (int i = count - 1; i >= 0; --i) {
|
| - const QMetaMethod m = meta->method(i);
|
| -
|
| - // Don't choose private methods
|
| - if (m.access() == QMetaMethod::Private && !allowPrivate)
|
| - continue;
|
| -
|
| - // try and find all matching named methods
|
| - if (m.signature() == signature)
|
| - matchingIndices.append(i);
|
| - else if (overloads) {
|
| - QByteArray rawsignature = m.signature();
|
| - rawsignature.truncate(rawsignature.indexOf('('));
|
| - if (rawsignature == signature)
|
| - matchingIndices.append(i);
|
| - }
|
| - }
|
| -
|
| - int chosenIndex = -1;
|
| - *pError = 0;
|
| - QVector<QtMethodMatchType> chosenTypes;
|
| -
|
| - QVarLengthArray<QVariant, 10> args;
|
| - QVector<QtMethodMatchData> candidates;
|
| - QVector<QtMethodMatchData> unresolved;
|
| - QVector<int> tooFewArgs;
|
| - QVector<int> conversionFailed;
|
| -
|
| - foreach(int index, matchingIndices) {
|
| - QMetaMethod method = meta->method(index);
|
| -
|
| - QVector<QtMethodMatchType> types;
|
| - bool unresolvedTypes = false;
|
| -
|
| - // resolve return type
|
| - QByteArray returnTypeName = method.typeName();
|
| - int rtype = QMetaType::type(returnTypeName);
|
| - if ((rtype == 0) && !returnTypeName.isEmpty()) {
|
| - if (returnTypeName == "QVariant") {
|
| - types.append(QtMethodMatchType::variant());
|
| - } else if (returnTypeName.endsWith('*')) {
|
| - types.append(QtMethodMatchType::metaType(QMetaType::VoidStar, returnTypeName));
|
| - } else {
|
| - int enumIndex = indexOfMetaEnum(meta, returnTypeName);
|
| - if (enumIndex != -1)
|
| - types.append(QtMethodMatchType::metaEnum(enumIndex, returnTypeName));
|
| - else {
|
| - unresolvedTypes = true;
|
| - types.append(QtMethodMatchType::unresolved(returnTypeName));
|
| - }
|
| - }
|
| - } else {
|
| - if (returnTypeName == "QVariant")
|
| - types.append(QtMethodMatchType::variant());
|
| - else
|
| - types.append(QtMethodMatchType::metaType(rtype, returnTypeName));
|
| - }
|
| -
|
| - // resolve argument types
|
| - QList<QByteArray> parameterTypeNames = method.parameterTypes();
|
| - for (int i = 0; i < parameterTypeNames.count(); ++i) {
|
| - QByteArray argTypeName = parameterTypeNames.at(i);
|
| - int atype = QMetaType::type(argTypeName);
|
| - if (atype == 0) {
|
| - if (argTypeName == "QVariant") {
|
| - types.append(QtMethodMatchType::variant());
|
| - } else {
|
| - int enumIndex = indexOfMetaEnum(meta, argTypeName);
|
| - if (enumIndex != -1)
|
| - types.append(QtMethodMatchType::metaEnum(enumIndex, argTypeName));
|
| - else {
|
| - unresolvedTypes = true;
|
| - types.append(QtMethodMatchType::unresolved(argTypeName));
|
| - }
|
| - }
|
| - } else {
|
| - if (argTypeName == "QVariant")
|
| - types.append(QtMethodMatchType::variant());
|
| - else
|
| - types.append(QtMethodMatchType::metaType(atype, argTypeName));
|
| - }
|
| - }
|
| -
|
| - // If the native method requires more arguments than what was passed from JavaScript
|
| - if (jsArgs.size() < (types.count() - 1)) {
|
| - qMatchDebug() << "Match:too few args for" << method.signature();
|
| - tooFewArgs.append(index);
|
| - continue;
|
| - }
|
| -
|
| - if (unresolvedTypes) {
|
| - qMatchDebug() << "Match:unresolved arg types for" << method.signature();
|
| - // remember it so we can give an error message later, if necessary
|
| - unresolved.append(QtMethodMatchData(/*matchDistance=*/INT_MAX, index,
|
| - types, QVarLengthArray<QVariant, 10>()));
|
| - continue;
|
| - }
|
| -
|
| - // Now convert arguments
|
| - if (args.count() != types.count())
|
| - args.resize(types.count());
|
| -
|
| - QtMethodMatchType retType = types[0];
|
| - args[0] = QVariant(retType.typeId(), (void *)0); // the return value
|
| -
|
| - bool converted = true;
|
| - int matchDistance = 0;
|
| - for (int i = 0; converted && i < types.count() - 1; ++i) {
|
| - JSValuePtr arg = i < jsArgs.size() ? jsArgs.at(exec, i) : jsUndefined();
|
| -
|
| - int argdistance = -1;
|
| - QVariant v = convertValueToQVariant(exec, arg, types.at(i+1).typeId(), &argdistance);
|
| - if (argdistance >= 0) {
|
| - matchDistance += argdistance;
|
| - args[i+1] = v;
|
| - } else {
|
| - qMatchDebug() << "failed to convert argument " << i << "type" << types.at(i+1).typeId() << QMetaType::typeName(types.at(i+1).typeId());
|
| - converted = false;
|
| - }
|
| - }
|
| -
|
| - qMatchDebug() << "Match: " << method.signature() << (converted ? "converted":"failed to convert") << "distance " << matchDistance;
|
| -
|
| - if (converted) {
|
| - if ((jsArgs.size() == types.count() - 1)
|
| - && (matchDistance == 0)) {
|
| - // perfect match, use this one
|
| - chosenIndex = index;
|
| - break;
|
| - } else {
|
| - QtMethodMatchData currentMatch(matchDistance, index, types, args);
|
| - if (candidates.isEmpty()) {
|
| - candidates.append(currentMatch);
|
| - } else {
|
| - QtMethodMatchData bestMatchSoFar = candidates.at(0);
|
| - if ((args.count() > bestMatchSoFar.args.count())
|
| - || ((args.count() == bestMatchSoFar.args.count())
|
| - && (matchDistance <= bestMatchSoFar.matchDistance))) {
|
| - candidates.prepend(currentMatch);
|
| - } else {
|
| - candidates.append(currentMatch);
|
| - }
|
| - }
|
| - }
|
| - } else {
|
| - conversionFailed.append(index);
|
| - }
|
| -
|
| - if (!overloads)
|
| - break;
|
| - }
|
| -
|
| - if (chosenIndex == -1 && candidates.count() == 0) {
|
| - // No valid functions at all - format an error message
|
| - if (!conversionFailed.isEmpty()) {
|
| - QString message = QString::fromLatin1("incompatible type of argument(s) in call to %0(); candidates were\n")
|
| - .arg(QLatin1String(signature));
|
| - for (int i = 0; i < conversionFailed.size(); ++i) {
|
| - if (i > 0)
|
| - message += QLatin1String("\n");
|
| - QMetaMethod mtd = meta->method(conversionFailed.at(i));
|
| - message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
|
| - }
|
| - *pError = throwError(exec, TypeError, message.toLatin1().constData());
|
| - } else if (!unresolved.isEmpty()) {
|
| - QtMethodMatchData argsInstance = unresolved.first();
|
| - int unresolvedIndex = argsInstance.firstUnresolvedIndex();
|
| - Q_ASSERT(unresolvedIndex != -1);
|
| - QtMethodMatchType unresolvedType = argsInstance.types.at(unresolvedIndex);
|
| - QString message = QString::fromLatin1("cannot call %0(): unknown type `%1'")
|
| - .arg(QString::fromLatin1(signature))
|
| - .arg(QLatin1String(unresolvedType.name()));
|
| - *pError = throwError(exec, TypeError, message.toLatin1().constData());
|
| - } else {
|
| - QString message = QString::fromLatin1("too few arguments in call to %0(); candidates are\n")
|
| - .arg(QLatin1String(signature));
|
| - for (int i = 0; i < tooFewArgs.size(); ++i) {
|
| - if (i > 0)
|
| - message += QLatin1String("\n");
|
| - QMetaMethod mtd = meta->method(tooFewArgs.at(i));
|
| - message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
|
| - }
|
| - *pError = throwError(exec, SyntaxError, message.toLatin1().constData());
|
| - }
|
| - }
|
| -
|
| - if (chosenIndex == -1 && candidates.count() > 0) {
|
| - QtMethodMatchData bestMatch = candidates.at(0);
|
| - if ((candidates.size() > 1)
|
| - && (bestMatch.args.count() == candidates.at(1).args.count())
|
| - && (bestMatch.matchDistance == candidates.at(1).matchDistance)) {
|
| - // ambiguous call
|
| - QString message = QString::fromLatin1("ambiguous call of overloaded function %0(); candidates were\n")
|
| - .arg(QLatin1String(signature));
|
| - for (int i = 0; i < candidates.size(); ++i) {
|
| - // Only candidate for overload if argument count and match distance is same as best match
|
| - if (candidates.at(i).args.count() == bestMatch.args.count()
|
| - || candidates.at(i).matchDistance == bestMatch.matchDistance) {
|
| - if (i > 0)
|
| - message += QLatin1String("\n");
|
| - QMetaMethod mtd = meta->method(candidates.at(i).index);
|
| - message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
|
| - }
|
| - }
|
| - *pError = throwError(exec, TypeError, message.toLatin1().constData());
|
| - } else {
|
| - chosenIndex = bestMatch.index;
|
| - args = bestMatch.args;
|
| - }
|
| - }
|
| -
|
| - if (chosenIndex != -1) {
|
| - /* Copy the stuff over */
|
| - int i;
|
| - vars.resize(args.count());
|
| - for (i=0; i < args.count(); i++) {
|
| - vars[i] = args[i];
|
| - vvars[i] = vars[i].data();
|
| - }
|
| - }
|
| -
|
| - return chosenIndex;
|
| -}
|
| -
|
| -// Signals are not fuzzy matched as much as methods
|
| -static int findSignalIndex(const QMetaObject* meta, int initialIndex, QByteArray signature)
|
| -{
|
| - int index = initialIndex;
|
| - QMetaMethod method = meta->method(index);
|
| - bool overloads = !signature.contains('(');
|
| - if (overloads && (method.attributes() & QMetaMethod::Cloned)) {
|
| - // find the most general method
|
| - do {
|
| - method = meta->method(--index);
|
| - } while (method.attributes() & QMetaMethod::Cloned);
|
| - }
|
| - return index;
|
| -}
|
| -
|
| -QtRuntimeMetaMethod::QtRuntimeMetaMethod(ExecState* exec, const Identifier& ident, PassRefPtr<QtInstance> inst, int index, const QByteArray& signature, bool allowPrivate)
|
| - : QtRuntimeMethod (new QtRuntimeMetaMethodData(), exec, ident, inst)
|
| -{
|
| - QW_D(QtRuntimeMetaMethod);
|
| - d->m_signature = signature;
|
| - d->m_index = index;
|
| - d->m_connect = 0;
|
| - d->m_disconnect = 0;
|
| - d->m_allowPrivate = allowPrivate;
|
| -}
|
| -
|
| -void QtRuntimeMetaMethod::mark()
|
| -{
|
| - QtRuntimeMethod::mark();
|
| - QW_D(QtRuntimeMetaMethod);
|
| - if (d->m_connect)
|
| - d->m_connect->mark();
|
| - if (d->m_disconnect)
|
| - d->m_disconnect->mark();
|
| -}
|
| -
|
| -JSValuePtr QtRuntimeMetaMethod::call(ExecState* exec, JSObject* functionObject, JSValuePtr thisValue, const ArgList& args)
|
| -{
|
| - QtRuntimeMetaMethodData* d = static_cast<QtRuntimeMetaMethod *>(functionObject)->d_func();
|
| -
|
| - // We're limited to 10 args
|
| - if (args.size() > 10)
|
| - return jsUndefined();
|
| -
|
| - // We have to pick a method that matches..
|
| - JSLock lock(false);
|
| -
|
| - QObject *obj = d->m_instance->getObject();
|
| - if (obj) {
|
| - QVarLengthArray<QVariant, 10> vargs;
|
| - void *qargs[11];
|
| -
|
| - int methodIndex;
|
| - JSObject* errorObj = 0;
|
| - if ((methodIndex = findMethodIndex(exec, obj->metaObject(), d->m_signature, d->m_allowPrivate, args, vargs, (void **)qargs, &errorObj)) != -1) {
|
| - if (obj->qt_metacall(QMetaObject::InvokeMetaMethod, methodIndex, qargs) >= 0)
|
| - return jsUndefined();
|
| -
|
| - if (vargs[0].isValid())
|
| - return convertQVariantToValue(exec, d->m_instance->rootObject(), vargs[0]);
|
| - }
|
| -
|
| - if (errorObj)
|
| - return errorObj;
|
| - } else {
|
| - return throwError(exec, GeneralError, "cannot call function of deleted QObject");
|
| - }
|
| -
|
| - // void functions return undefined
|
| - return jsUndefined();
|
| -}
|
| -
|
| -CallType QtRuntimeMetaMethod::getCallData(CallData& callData)
|
| -{
|
| - callData.native.function = call;
|
| - return CallTypeHost;
|
| -}
|
| -
|
| -bool QtRuntimeMetaMethod::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
|
| -{
|
| - if (propertyName == "connect") {
|
| - slot.setCustom(this, connectGetter);
|
| - return true;
|
| - } else if (propertyName == "disconnect") {
|
| - slot.setCustom(this, disconnectGetter);
|
| - return true;
|
| - } else if (propertyName == exec->propertyNames().length) {
|
| - slot.setCustom(this, lengthGetter);
|
| - return true;
|
| - }
|
| -
|
| - return QtRuntimeMethod::getOwnPropertySlot(exec, propertyName, slot);
|
| -}
|
| -
|
| -JSValuePtr QtRuntimeMetaMethod::lengthGetter(ExecState* exec, const Identifier&, const PropertySlot&)
|
| -{
|
| - // QtScript always returns 0
|
| - return jsNumber(exec, 0);
|
| -}
|
| -
|
| -JSValuePtr QtRuntimeMetaMethod::connectGetter(ExecState* exec, const Identifier& ident, const PropertySlot& slot)
|
| -{
|
| - QtRuntimeMetaMethod* thisObj = static_cast<QtRuntimeMetaMethod*>(asObject(slot.slotBase()));
|
| - QW_DS(QtRuntimeMetaMethod, thisObj);
|
| -
|
| - if (!d->m_connect)
|
| - d->m_connect = new (exec) QtRuntimeConnectionMethod(exec, ident, true, d->m_instance, d->m_index, d->m_signature);
|
| - return d->m_connect;
|
| -}
|
| -
|
| -JSValuePtr QtRuntimeMetaMethod::disconnectGetter(ExecState* exec, const Identifier& ident, const PropertySlot& slot)
|
| -{
|
| - QtRuntimeMetaMethod* thisObj = static_cast<QtRuntimeMetaMethod*>(asObject(slot.slotBase()));
|
| - QW_DS(QtRuntimeMetaMethod, thisObj);
|
| -
|
| - if (!d->m_disconnect)
|
| - d->m_disconnect = new (exec) QtRuntimeConnectionMethod(exec, ident, false, d->m_instance, d->m_index, d->m_signature);
|
| - return d->m_disconnect;
|
| -}
|
| -
|
| -// ===============
|
| -
|
| -QMultiMap<QObject*, QtConnectionObject*> QtRuntimeConnectionMethod::connections;
|
| -
|
| -QtRuntimeConnectionMethod::QtRuntimeConnectionMethod(ExecState* exec, const Identifier& ident, bool isConnect, PassRefPtr<QtInstance> inst, int index, const QByteArray& signature)
|
| - : QtRuntimeMethod (new QtRuntimeConnectionMethodData(), exec, ident, inst)
|
| -{
|
| - QW_D(QtRuntimeConnectionMethod);
|
| -
|
| - d->m_signature = signature;
|
| - d->m_index = index;
|
| - d->m_isConnect = isConnect;
|
| -}
|
| -
|
| -JSValuePtr QtRuntimeConnectionMethod::call(ExecState* exec, JSObject* functionObject, JSValuePtr thisValue, const ArgList& args)
|
| -{
|
| - QtRuntimeConnectionMethodData* d = static_cast<QtRuntimeConnectionMethod *>(functionObject)->d_func();
|
| -
|
| - JSLock lock(false);
|
| -
|
| - QObject* sender = d->m_instance->getObject();
|
| -
|
| - if (sender) {
|
| -
|
| - JSObject* thisObject = exec->lexicalGlobalObject();
|
| - JSObject* funcObject = 0;
|
| -
|
| - // QtScript checks signalness first, arguments second
|
| - int signalIndex = -1;
|
| -
|
| - // Make sure the initial index is a signal
|
| - QMetaMethod m = sender->metaObject()->method(d->m_index);
|
| - if (m.methodType() == QMetaMethod::Signal)
|
| - signalIndex = findSignalIndex(sender->metaObject(), d->m_index, d->m_signature);
|
| -
|
| - if (signalIndex != -1) {
|
| - if (args.size() == 1) {
|
| - funcObject = args.at(exec, 0).toObject(exec);
|
| - CallData callData;
|
| - if (funcObject->getCallData(callData) == CallTypeNone) {
|
| - if (d->m_isConnect)
|
| - return throwError(exec, TypeError, "QtMetaMethod.connect: target is not a function");
|
| - else
|
| - return throwError(exec, TypeError, "QtMetaMethod.disconnect: target is not a function");
|
| - }
|
| - } else if (args.size() >= 2) {
|
| - if (args.at(exec, 0).isObject()) {
|
| - thisObject = args.at(exec, 0).toObject(exec);
|
| -
|
| - // Get the actual function to call
|
| - JSObject *asObj = args.at(exec, 1).toObject(exec);
|
| - CallData callData;
|
| - if (asObj->getCallData(callData) != CallTypeNone) {
|
| - // Function version
|
| - funcObject = asObj;
|
| - } else {
|
| - // Convert it to a string
|
| - UString funcName = args.at(exec, 1).toString(exec);
|
| - Identifier funcIdent(exec, funcName);
|
| -
|
| - // ### DropAllLocks
|
| - // This is resolved at this point in QtScript
|
| - JSValuePtr val = thisObject->get(exec, funcIdent);
|
| - JSObject* asFuncObj = val.toObject(exec);
|
| -
|
| - if (asFuncObj->getCallData(callData) != CallTypeNone) {
|
| - funcObject = asFuncObj;
|
| - } else {
|
| - if (d->m_isConnect)
|
| - return throwError(exec, TypeError, "QtMetaMethod.connect: target is not a function");
|
| - else
|
| - return throwError(exec, TypeError, "QtMetaMethod.disconnect: target is not a function");
|
| - }
|
| - }
|
| - } else {
|
| - if (d->m_isConnect)
|
| - return throwError(exec, TypeError, "QtMetaMethod.connect: thisObject is not an object");
|
| - else
|
| - return throwError(exec, TypeError, "QtMetaMethod.disconnect: thisObject is not an object");
|
| - }
|
| - } else {
|
| - if (d->m_isConnect)
|
| - return throwError(exec, GeneralError, "QtMetaMethod.connect: no arguments given");
|
| - else
|
| - return throwError(exec, GeneralError, "QtMetaMethod.disconnect: no arguments given");
|
| - }
|
| -
|
| - if (d->m_isConnect) {
|
| - // to connect, we need:
|
| - // target object [from ctor]
|
| - // target signal index etc. [from ctor]
|
| - // receiver function [from arguments]
|
| - // receiver this object [from arguments]
|
| -
|
| - QtConnectionObject* conn = new QtConnectionObject(d->m_instance, signalIndex, thisObject, funcObject);
|
| - bool ok = QMetaObject::connect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
|
| - if (!ok) {
|
| - delete conn;
|
| - QString msg = QString(QLatin1String("QtMetaMethod.connect: failed to connect to %1::%2()"))
|
| - .arg(QLatin1String(sender->metaObject()->className()))
|
| - .arg(QLatin1String(d->m_signature));
|
| - return throwError(exec, GeneralError, msg.toLatin1().constData());
|
| - }
|
| - else {
|
| - // Store connection
|
| - connections.insert(sender, conn);
|
| - }
|
| - } else {
|
| - // Now to find our previous connection object. Hmm.
|
| - QList<QtConnectionObject*> conns = connections.values(sender);
|
| - bool ret = false;
|
| -
|
| - foreach(QtConnectionObject* conn, conns) {
|
| - // Is this the right connection?
|
| - if (conn->match(sender, signalIndex, thisObject, funcObject)) {
|
| - // Yep, disconnect it
|
| - QMetaObject::disconnect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
|
| - delete conn; // this will also remove it from the map
|
| - ret = true;
|
| - break;
|
| - }
|
| - }
|
| -
|
| - if (!ret) {
|
| - QString msg = QString(QLatin1String("QtMetaMethod.disconnect: failed to disconnect from %1::%2()"))
|
| - .arg(QLatin1String(sender->metaObject()->className()))
|
| - .arg(QLatin1String(d->m_signature));
|
| - return throwError(exec, GeneralError, msg.toLatin1().constData());
|
| - }
|
| - }
|
| - } else {
|
| - QString msg = QString(QLatin1String("QtMetaMethod.%1: %2::%3() is not a signal"))
|
| - .arg(QLatin1String(d->m_isConnect ? "connect": "disconnect"))
|
| - .arg(QLatin1String(sender->metaObject()->className()))
|
| - .arg(QLatin1String(d->m_signature));
|
| - return throwError(exec, TypeError, msg.toLatin1().constData());
|
| - }
|
| - } else {
|
| - return throwError(exec, GeneralError, "cannot call function of deleted QObject");
|
| - }
|
| -
|
| - return jsUndefined();
|
| -}
|
| -
|
| -CallType QtRuntimeConnectionMethod::getCallData(CallData& callData)
|
| -{
|
| - callData.native.function = call;
|
| - return CallTypeHost;
|
| -}
|
| -
|
| -bool QtRuntimeConnectionMethod::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
|
| -{
|
| - if (propertyName == exec->propertyNames().length) {
|
| - slot.setCustom(this, lengthGetter);
|
| - return true;
|
| - }
|
| -
|
| - return QtRuntimeMethod::getOwnPropertySlot(exec, propertyName, slot);
|
| -}
|
| -
|
| -JSValuePtr QtRuntimeConnectionMethod::lengthGetter(ExecState* exec, const Identifier&, const PropertySlot&)
|
| -{
|
| - // we have one formal argument, and one optional
|
| - return jsNumber(exec, 1);
|
| -}
|
| -
|
| -// ===============
|
| -
|
| -QtConnectionObject::QtConnectionObject(PassRefPtr<QtInstance> instance, int signalIndex, JSObject* thisObject, JSObject* funcObject)
|
| - : m_instance(instance)
|
| - , m_signalIndex(signalIndex)
|
| - , m_originalObject(m_instance->getObject())
|
| - , m_thisObject(thisObject)
|
| - , m_funcObject(funcObject)
|
| -{
|
| - setParent(m_originalObject);
|
| - ASSERT(JSLock::currentThreadIsHoldingLock()); // so our ProtectedPtrs are safe
|
| -}
|
| -
|
| -QtConnectionObject::~QtConnectionObject()
|
| -{
|
| - // Remove us from the map of active connections
|
| - QtRuntimeConnectionMethod::connections.remove(m_originalObject, this);
|
| -}
|
| -
|
| -static const uint qt_meta_data_QtConnectionObject[] = {
|
| -
|
| - // content:
|
| - 1, // revision
|
| - 0, // classname
|
| - 0, 0, // classinfo
|
| - 1, 10, // methods
|
| - 0, 0, // properties
|
| - 0, 0, // enums/sets
|
| -
|
| - // slots: signature, parameters, type, tag, flags
|
| - 28, 27, 27, 27, 0x0a,
|
| -
|
| - 0 // eod
|
| -};
|
| -
|
| -static const char qt_meta_stringdata_QtConnectionObject[] = {
|
| - "JSC::Bindings::QtConnectionObject\0\0execute()\0"
|
| -};
|
| -
|
| -const QMetaObject QtConnectionObject::staticMetaObject = {
|
| - { &QObject::staticMetaObject, qt_meta_stringdata_QtConnectionObject,
|
| - qt_meta_data_QtConnectionObject, 0 }
|
| -};
|
| -
|
| -const QMetaObject *QtConnectionObject::metaObject() const
|
| -{
|
| - return &staticMetaObject;
|
| -}
|
| -
|
| -void *QtConnectionObject::qt_metacast(const char *_clname)
|
| -{
|
| - if (!_clname) return 0;
|
| - if (!strcmp(_clname, qt_meta_stringdata_QtConnectionObject))
|
| - return static_cast<void*>(const_cast<QtConnectionObject*>(this));
|
| - return QObject::qt_metacast(_clname);
|
| -}
|
| -
|
| -int QtConnectionObject::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
|
| -{
|
| - _id = QObject::qt_metacall(_c, _id, _a);
|
| - if (_id < 0)
|
| - return _id;
|
| - if (_c == QMetaObject::InvokeMetaMethod) {
|
| - switch (_id) {
|
| - case 0: execute(_a); break;
|
| - }
|
| - _id -= 1;
|
| - }
|
| - return _id;
|
| -}
|
| -
|
| -void QtConnectionObject::execute(void **argv)
|
| -{
|
| - QObject* obj = m_instance->getObject();
|
| - if (obj) {
|
| - const QMetaObject* meta = obj->metaObject();
|
| - const QMetaMethod method = meta->method(m_signalIndex);
|
| -
|
| - QList<QByteArray> parameterTypes = method.parameterTypes();
|
| -
|
| - int argc = parameterTypes.count();
|
| -
|
| - JSLock lock(false);
|
| -
|
| - // ### Should the Interpreter/ExecState come from somewhere else?
|
| - RefPtr<RootObject> ro = m_instance->rootObject();
|
| - if (ro) {
|
| - JSGlobalObject* globalobj = ro->globalObject();
|
| - if (globalobj) {
|
| - ExecState* exec = globalobj->globalExec();
|
| - if (exec) {
|
| - // Build the argument list (up to the formal argument length of the slot)
|
| - ArgList l;
|
| - // ### DropAllLocks?
|
| - int funcArgC = m_funcObject->get(exec, exec->propertyNames().length).toInt32(exec);
|
| - int argTotal = qMax(funcArgC, argc);
|
| - for(int i=0; i < argTotal; i++) {
|
| - if (i < argc) {
|
| - int argType = QMetaType::type(parameterTypes.at(i));
|
| - l.append(convertQVariantToValue(exec, ro, QVariant(argType, argv[i+1])));
|
| - } else {
|
| - l.append(jsUndefined());
|
| - }
|
| - }
|
| - CallData callData;
|
| - CallType callType = m_funcObject->getCallData(callData);
|
| - // Stuff in the __qt_sender property, if we can
|
| - if (m_funcObject->inherits(&JSFunction::info)) {
|
| - JSFunction* fimp = static_cast<JSFunction*>(m_funcObject.get());
|
| -
|
| - JSObject* qt_sender = QtInstance::getQtInstance(sender(), ro, QScriptEngine::QtOwnership)->createRuntimeObject(exec);
|
| - JSObject* wrapper = new (exec) JSObject(JSObject::createStructure(jsNull()));
|
| - PutPropertySlot slot;
|
| - wrapper->put(exec, Identifier(exec, "__qt_sender__"), qt_sender, slot);
|
| - ScopeChain oldsc = fimp->scope();
|
| - ScopeChain sc = oldsc;
|
| - sc.push(wrapper);
|
| - fimp->setScope(sc);
|
| -
|
| - call(exec, fimp, callType, callData, m_thisObject, l);
|
| - fimp->setScope(oldsc);
|
| - } else {
|
| - call(exec, m_funcObject, callType, callData, m_thisObject, l);
|
| - }
|
| - }
|
| - }
|
| - }
|
| - } else {
|
| - // A strange place to be - a deleted object emitted a signal here.
|
| - qWarning() << "sender deleted, cannot deliver signal";
|
| - }
|
| -}
|
| -
|
| -bool QtConnectionObject::match(QObject* sender, int signalIndex, JSObject* thisObject, JSObject *funcObject)
|
| -{
|
| - if (m_originalObject == sender && m_signalIndex == signalIndex
|
| - && thisObject == (JSObject*)m_thisObject && funcObject == (JSObject*)m_funcObject)
|
| - return true;
|
| - return false;
|
| -}
|
| -
|
| -// ===============
|
| -
|
| -template <typename T> QtArray<T>::QtArray(QList<T> list, QMetaType::Type type, PassRefPtr<RootObject> rootObject)
|
| - : Array(rootObject)
|
| - , m_list(list)
|
| - , m_type(type)
|
| -{
|
| - m_length = m_list.count();
|
| -}
|
| -
|
| -template <typename T> QtArray<T>::~QtArray ()
|
| -{
|
| -}
|
| -
|
| -template <typename T> RootObject* QtArray<T>::rootObject() const
|
| -{
|
| - return _rootObject && _rootObject->isValid() ? _rootObject.get() : 0;
|
| -}
|
| -
|
| -template <typename T> void QtArray<T>::setValueAt(ExecState* exec, unsigned index, JSValuePtr aValue) const
|
| -{
|
| - // QtScript sets the value, but doesn't forward it to the original source
|
| - // (e.g. if you do 'object.intList[5] = 6', the object is not updated, but the
|
| - // copy of the list is).
|
| - int dist = -1;
|
| - QVariant val = convertValueToQVariant(exec, aValue, m_type, &dist);
|
| -
|
| - if (dist >= 0) {
|
| - m_list[index] = val.value<T>();
|
| - }
|
| -}
|
| -
|
| -
|
| -template <typename T> JSValuePtr QtArray<T>::valueAt(ExecState *exec, unsigned int index) const
|
| -{
|
| - if (index < m_length) {
|
| - T val = m_list.at(index);
|
| - return convertQVariantToValue(exec, rootObject(), QVariant::fromValue(val));
|
| - }
|
| -
|
| - return jsUndefined();
|
| -}
|
| -
|
| -// ===============
|
| -
|
| -} }
|
| -
|
| +/*
|
| + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
|
| + *
|
| + * This library is free software; you can redistribute it and/or
|
| + * modify it under the terms of the GNU Lesser General Public
|
| + * License as published by the Free Software Foundation; either
|
| + * version 2 of the License, or (at your option) any later version.
|
| + *
|
| + * This library is distributed in the hope that it will be useful,
|
| + * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| + * Lesser General Public License for more details.
|
| + *
|
| + * You should have received a copy of the GNU Lesser General Public
|
| + * License along with this library; if not, write to the Free Software
|
| + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| + *
|
| + */
|
| +
|
| +#include "config.h"
|
| +#include "qt_runtime.h"
|
| +
|
| +#include "DateInstance.h"
|
| +#include "DateMath.h"
|
| +#include "DatePrototype.h"
|
| +#include "FunctionPrototype.h"
|
| +#include "Interpreter.h"
|
| +#include "JSArray.h"
|
| +#include "JSByteArray.h"
|
| +#include "JSDOMBinding.h"
|
| +#include "JSGlobalObject.h"
|
| +#include "JSLock.h"
|
| +#include "JSObject.h"
|
| +#include "ObjectPrototype.h"
|
| +#include "PropertyNameArray.h"
|
| +#include "RegExpConstructor.h"
|
| +#include "RegExpObject.h"
|
| +#include "qdatetime.h"
|
| +#include "qdebug.h"
|
| +#include "qmetaobject.h"
|
| +#include "qmetatype.h"
|
| +#include "qobject.h"
|
| +#include "qstringlist.h"
|
| +#include "qt_instance.h"
|
| +#include "qvarlengtharray.h"
|
| +#include <JSFunction.h>
|
| +#include <limits.h>
|
| +#include <runtime.h>
|
| +#include <runtime_array.h>
|
| +#include <runtime_object.h>
|
| +#include "BooleanObject.h"
|
| +
|
| +// QtScript has these
|
| +Q_DECLARE_METATYPE(QObjectList);
|
| +Q_DECLARE_METATYPE(QList<int>);
|
| +Q_DECLARE_METATYPE(QVariant);
|
| +
|
| +using namespace WebCore;
|
| +
|
| +namespace JSC {
|
| +namespace Bindings {
|
| +
|
| +// Debugging
|
| +//#define QTWK_RUNTIME_CONVERSION_DEBUG
|
| +//#define QTWK_RUNTIME_MATCH_DEBUG
|
| +
|
| +class QWKNoDebug
|
| +{
|
| +public:
|
| + inline QWKNoDebug(){}
|
| + inline ~QWKNoDebug(){}
|
| +
|
| + template<typename T>
|
| + inline QWKNoDebug &operator<<(const T &) { return *this; }
|
| +};
|
| +
|
| +#ifdef QTWK_RUNTIME_CONVERSION_DEBUG
|
| +#define qConvDebug() qDebug()
|
| +#else
|
| +#define qConvDebug() QWKNoDebug()
|
| +#endif
|
| +
|
| +#ifdef QTWK_RUNTIME_MATCH_DEBUG
|
| +#define qMatchDebug() qDebug()
|
| +#else
|
| +#define qMatchDebug() QWKNoDebug()
|
| +#endif
|
| +
|
| +typedef enum {
|
| + Variant = 0,
|
| + Number,
|
| + Boolean,
|
| + String,
|
| + Date,
|
| + RegExp,
|
| + Array,
|
| + QObj,
|
| + Object,
|
| + Null,
|
| + RTArray,
|
| + JSByteArray
|
| +} JSRealType;
|
| +
|
| +#if defined(QTWK_RUNTIME_CONVERSION_DEBUG) || defined(QTWK_RUNTIME_MATCH_DEBUG)
|
| +QDebug operator<<(QDebug dbg, const JSRealType &c)
|
| +{
|
| + const char *map[] = { "Variant", "Number", "Boolean", "String", "Date",
|
| + "RegExp", "Array", "RTObject", "Object", "Null", "RTArray"};
|
| +
|
| + dbg.nospace() << "JSType(" << ((int)c) << ", " << map[c] << ")";
|
| +
|
| + return dbg.space();
|
| +}
|
| +#endif
|
| +
|
| +static JSRealType valueRealType(ExecState* exec, JSValuePtr val)
|
| +{
|
| + if (val.isNumber())
|
| + return Number;
|
| + else if (val.isString())
|
| + return String;
|
| + else if (val.isBoolean())
|
| + return Boolean;
|
| + else if (val.isNull())
|
| + return Null;
|
| + else if (exec->interpreter()->isJSByteArray(val))
|
| + return JSByteArray;
|
| + else if (val.isObject()) {
|
| + JSObject *object = val.toObject(exec);
|
| + if (object->inherits(&RuntimeArray::s_info)) // RuntimeArray 'inherits' from Array, but not in C++
|
| + return RTArray;
|
| + else if (object->inherits(&JSArray::info))
|
| + return Array;
|
| + else if (object->inherits(&DateInstance::info))
|
| + return Date;
|
| + else if (object->inherits(&RegExpObject::info))
|
| + return RegExp;
|
| + else if (object->inherits(&RuntimeObjectImp::s_info))
|
| + return QObj;
|
| + return Object;
|
| + }
|
| +
|
| + return String; // I don't know.
|
| +}
|
| +
|
| +QVariant convertValueToQVariant(ExecState* exec, JSValuePtr value, QMetaType::Type hint, int *distance, HashSet<JSObject*>* visitedObjects)
|
| +{
|
| + JSObject* object = 0;
|
| + if (value.isObject()) {
|
| + object = value.toObject(exec);
|
| + if (visitedObjects->contains(object))
|
| + return QVariant();
|
| +
|
| + visitedObjects->add(object);
|
| + }
|
| +
|
| + // check magic pointer values before dereferencing value
|
| + if (value == jsNaN(exec)
|
| + || (value == jsUndefined()
|
| + && hint != QMetaType::QString
|
| + && hint != (QMetaType::Type) qMetaTypeId<QVariant>())) {
|
| + if (distance)
|
| + *distance = -1;
|
| + return QVariant();
|
| + }
|
| +
|
| + JSLock lock(false);
|
| + JSRealType type = valueRealType(exec, value);
|
| + if (hint == QMetaType::Void) {
|
| + switch(type) {
|
| + case Number:
|
| + hint = QMetaType::Double;
|
| + break;
|
| + case Boolean:
|
| + hint = QMetaType::Bool;
|
| + break;
|
| + case String:
|
| + default:
|
| + hint = QMetaType::QString;
|
| + break;
|
| + case Date:
|
| + hint = QMetaType::QDateTime;
|
| + break;
|
| + case RegExp:
|
| + hint = QMetaType::QRegExp;
|
| + break;
|
| + case Object:
|
| + if (object->inherits(&NumberObject::info))
|
| + hint = QMetaType::Double;
|
| + else if (object->inherits(&BooleanObject::info))
|
| + hint = QMetaType::Bool;
|
| + else
|
| + hint = QMetaType::QVariantMap;
|
| + break;
|
| + case QObj:
|
| + hint = QMetaType::QObjectStar;
|
| + break;
|
| + case JSByteArray:
|
| + hint = QMetaType::QByteArray;
|
| + break;
|
| + case Array:
|
| + case RTArray:
|
| + hint = QMetaType::QVariantList;
|
| + break;
|
| + }
|
| + }
|
| +
|
| + qConvDebug() << "convertValueToQVariant: jstype is " << type << ", hint is" << hint;
|
| +
|
| + if (value == jsNull()
|
| + && hint != QMetaType::QObjectStar
|
| + && hint != QMetaType::VoidStar
|
| + && hint != QMetaType::QString
|
| + && hint != (QMetaType::Type) qMetaTypeId<QVariant>()) {
|
| + if (distance)
|
| + *distance = -1;
|
| + return QVariant();
|
| + }
|
| +
|
| + QVariant ret;
|
| + int dist = -1;
|
| + switch (hint) {
|
| + case QMetaType::Bool:
|
| + if (type == Object && object->inherits(&BooleanObject::info))
|
| + ret = QVariant(asBooleanObject(value)->internalValue().toBoolean(exec));
|
| + else
|
| + ret = QVariant(value.toBoolean(exec));
|
| + if (type == Boolean)
|
| + dist = 0;
|
| + else
|
| + dist = 10;
|
| + break;
|
| +
|
| + case QMetaType::Int:
|
| + case QMetaType::UInt:
|
| + case QMetaType::Long:
|
| + case QMetaType::ULong:
|
| + case QMetaType::LongLong:
|
| + case QMetaType::ULongLong:
|
| + case QMetaType::Short:
|
| + case QMetaType::UShort:
|
| + case QMetaType::Float:
|
| + case QMetaType::Double:
|
| + ret = QVariant(value.toNumber(exec));
|
| + ret.convert((QVariant::Type)hint);
|
| + if (type == Number) {
|
| + switch (hint) {
|
| + case QMetaType::Double:
|
| + dist = 0;
|
| + break;
|
| + case QMetaType::Float:
|
| + dist = 1;
|
| + break;
|
| + case QMetaType::LongLong:
|
| + case QMetaType::ULongLong:
|
| + dist = 2;
|
| + break;
|
| + case QMetaType::Long:
|
| + case QMetaType::ULong:
|
| + dist = 3;
|
| + break;
|
| + case QMetaType::Int:
|
| + case QMetaType::UInt:
|
| + dist = 4;
|
| + break;
|
| + case QMetaType::Short:
|
| + case QMetaType::UShort:
|
| + dist = 5;
|
| + break;
|
| + break;
|
| + default:
|
| + dist = 10;
|
| + break;
|
| + }
|
| + } else {
|
| + dist = 10;
|
| + }
|
| + break;
|
| +
|
| + case QMetaType::QChar:
|
| + if (type == Number || type == Boolean) {
|
| + ret = QVariant(QChar((ushort)value.toNumber(exec)));
|
| + if (type == Boolean)
|
| + dist = 3;
|
| + else
|
| + dist = 6;
|
| + } else {
|
| + UString str = value.toString(exec);
|
| + ret = QVariant(QChar(str.size() ? *(const ushort*)str.rep()->data() : 0));
|
| + if (type == String)
|
| + dist = 3;
|
| + else
|
| + dist = 10;
|
| + }
|
| + break;
|
| +
|
| + case QMetaType::QString: {
|
| + if (value.isUndefinedOrNull()) {
|
| + if (distance)
|
| + *distance = 1;
|
| + return QString();
|
| + } else {
|
| + UString ustring = value.toString(exec);
|
| + ret = QVariant(QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size()));
|
| + if (type == String)
|
| + dist = 0;
|
| + else
|
| + dist = 10;
|
| + }
|
| + break;
|
| + }
|
| +
|
| + case QMetaType::QVariantMap:
|
| + if (type == Object || type == Array || type == RTArray) {
|
| + // Enumerate the contents of the object
|
| + PropertyNameArray properties(exec);
|
| + object->getPropertyNames(exec, properties);
|
| + PropertyNameArray::const_iterator it = properties.begin();
|
| +
|
| + QVariantMap result;
|
| + int objdist = 0;
|
| + while(it != properties.end()) {
|
| + if (object->propertyIsEnumerable(exec, *it)) {
|
| + JSValuePtr val = object->get(exec, *it);
|
| + QVariant v = convertValueToQVariant(exec, val, QMetaType::Void, &objdist, visitedObjects);
|
| + if (objdist >= 0) {
|
| + UString ustring = (*it).ustring();
|
| + QString id = QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size());
|
| + result.insert(id, v);
|
| + }
|
| + }
|
| + ++it;
|
| + }
|
| + dist = 1;
|
| + ret = QVariant(result);
|
| + }
|
| + break;
|
| +
|
| + case QMetaType::QVariantList:
|
| + if (type == RTArray) {
|
| + RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
|
| +
|
| + QVariantList result;
|
| + int len = rtarray->getLength();
|
| + int objdist = 0;
|
| + qConvDebug() << "converting a " << len << " length Array";
|
| + for (int i = 0; i < len; ++i) {
|
| + JSValuePtr val = rtarray->getConcreteArray()->valueAt(exec, i);
|
| + result.append(convertValueToQVariant(exec, val, QMetaType::Void, &objdist, visitedObjects));
|
| + if (objdist == -1) {
|
| + qConvDebug() << "Failed converting element at index " << i;
|
| + break; // Failed converting a list entry, so fail the array
|
| + }
|
| + }
|
| + if (objdist != -1) {
|
| + dist = 5;
|
| + ret = QVariant(result);
|
| + }
|
| + } else if (type == Array) {
|
| + JSArray* array = static_cast<JSArray*>(object);
|
| +
|
| + QVariantList result;
|
| + int len = array->length();
|
| + int objdist = 0;
|
| + qConvDebug() << "converting a " << len << " length Array";
|
| + for (int i = 0; i < len; ++i) {
|
| + JSValuePtr val = array->get(exec, i);
|
| + result.append(convertValueToQVariant(exec, val, QMetaType::Void, &objdist, visitedObjects));
|
| + if (objdist == -1) {
|
| + qConvDebug() << "Failed converting element at index " << i;
|
| + break; // Failed converting a list entry, so fail the array
|
| + }
|
| + }
|
| + if (objdist != -1) {
|
| + dist = 5;
|
| + ret = QVariant(result);
|
| + }
|
| + } else {
|
| + // Make a single length array
|
| + int objdist;
|
| + qConvDebug() << "making a single length variantlist";
|
| + QVariant var = convertValueToQVariant(exec, value, QMetaType::Void, &objdist, visitedObjects);
|
| + if (objdist != -1) {
|
| + QVariantList result;
|
| + result << var;
|
| + ret = QVariant(result);
|
| + dist = 10;
|
| + } else {
|
| + qConvDebug() << "failed making single length varlist";
|
| + }
|
| + }
|
| + break;
|
| +
|
| + case QMetaType::QStringList: {
|
| + if (type == RTArray) {
|
| + RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
|
| +
|
| + QStringList result;
|
| + int len = rtarray->getLength();
|
| + for (int i = 0; i < len; ++i) {
|
| + JSValuePtr val = rtarray->getConcreteArray()->valueAt(exec, i);
|
| + UString ustring = val.toString(exec);
|
| + QString qstring = QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size());
|
| +
|
| + result.append(qstring);
|
| + }
|
| + dist = 5;
|
| + ret = QVariant(result);
|
| + } else if (type == Array) {
|
| + JSArray* array = static_cast<JSArray*>(object);
|
| +
|
| + QStringList result;
|
| + int len = array->length();
|
| + for (int i = 0; i < len; ++i) {
|
| + JSValuePtr val = array->get(exec, i);
|
| + UString ustring = val.toString(exec);
|
| + QString qstring = QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size());
|
| +
|
| + result.append(qstring);
|
| + }
|
| + dist = 5;
|
| + ret = QVariant(result);
|
| + } else {
|
| + // Make a single length array
|
| + UString ustring = value.toString(exec);
|
| + QString qstring = QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size());
|
| + QStringList result;
|
| + result.append(qstring);
|
| + ret = QVariant(result);
|
| + dist = 10;
|
| + }
|
| + break;
|
| + }
|
| +
|
| + case QMetaType::QByteArray: {
|
| + if (type == JSByteArray) {
|
| + WTF::ByteArray* arr = asByteArray(value)->storage();
|
| + ret = QVariant(QByteArray(reinterpret_cast<const char*>(arr->data()), arr->length()));
|
| + dist = 0;
|
| + } else {
|
| + UString ustring = value.toString(exec);
|
| + ret = QVariant(QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size()).toLatin1());
|
| + if (type == String)
|
| + dist = 5;
|
| + else
|
| + dist = 10;
|
| + }
|
| + break;
|
| + }
|
| +
|
| + case QMetaType::QDateTime:
|
| + case QMetaType::QDate:
|
| + case QMetaType::QTime:
|
| + if (type == Date) {
|
| + DateInstance* date = static_cast<DateInstance*>(object);
|
| + GregorianDateTime gdt;
|
| + date->getUTCTime(gdt);
|
| + if (hint == QMetaType::QDateTime) {
|
| + ret = QDateTime(QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay), QTime(gdt.hour, gdt.minute, gdt.second), Qt::UTC);
|
| + dist = 0;
|
| + } else if (hint == QMetaType::QDate) {
|
| + ret = QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay);
|
| + dist = 1;
|
| + } else {
|
| + ret = QTime(gdt.hour + 1900, gdt.minute, gdt.second);
|
| + dist = 2;
|
| + }
|
| + } else if (type == Number) {
|
| + double b = value.toNumber(exec);
|
| + GregorianDateTime gdt;
|
| + msToGregorianDateTime(b, true, gdt);
|
| + if (hint == QMetaType::QDateTime) {
|
| + ret = QDateTime(QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay), QTime(gdt.hour, gdt.minute, gdt.second), Qt::UTC);
|
| + dist = 6;
|
| + } else if (hint == QMetaType::QDate) {
|
| + ret = QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay);
|
| + dist = 8;
|
| + } else {
|
| + ret = QTime(gdt.hour, gdt.minute, gdt.second);
|
| + dist = 10;
|
| + }
|
| + } else if (type == String) {
|
| + UString ustring = value.toString(exec);
|
| + QString qstring = QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size());
|
| +
|
| + if (hint == QMetaType::QDateTime) {
|
| + QDateTime dt = QDateTime::fromString(qstring, Qt::ISODate);
|
| + if (!dt.isValid())
|
| + dt = QDateTime::fromString(qstring, Qt::TextDate);
|
| + if (!dt.isValid())
|
| + dt = QDateTime::fromString(qstring, Qt::SystemLocaleDate);
|
| + if (!dt.isValid())
|
| + dt = QDateTime::fromString(qstring, Qt::LocaleDate);
|
| + if (dt.isValid()) {
|
| + ret = dt;
|
| + dist = 2;
|
| + }
|
| + } else if (hint == QMetaType::QDate) {
|
| + QDate dt = QDate::fromString(qstring, Qt::ISODate);
|
| + if (!dt.isValid())
|
| + dt = QDate::fromString(qstring, Qt::TextDate);
|
| + if (!dt.isValid())
|
| + dt = QDate::fromString(qstring, Qt::SystemLocaleDate);
|
| + if (!dt.isValid())
|
| + dt = QDate::fromString(qstring, Qt::LocaleDate);
|
| + if (dt.isValid()) {
|
| + ret = dt;
|
| + dist = 3;
|
| + }
|
| + } else {
|
| + QTime dt = QTime::fromString(qstring, Qt::ISODate);
|
| + if (!dt.isValid())
|
| + dt = QTime::fromString(qstring, Qt::TextDate);
|
| + if (!dt.isValid())
|
| + dt = QTime::fromString(qstring, Qt::SystemLocaleDate);
|
| + if (!dt.isValid())
|
| + dt = QTime::fromString(qstring, Qt::LocaleDate);
|
| + if (dt.isValid()) {
|
| + ret = dt;
|
| + dist = 3;
|
| + }
|
| + }
|
| + }
|
| + break;
|
| +
|
| + case QMetaType::QRegExp:
|
| + if (type == RegExp) {
|
| +/*
|
| + RegExpObject *re = static_cast<RegExpObject*>(object);
|
| +*/
|
| + // Attempt to convert.. a bit risky
|
| + UString ustring = value.toString(exec);
|
| + QString qstring = QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size());
|
| +
|
| + // this is of the form '/xxxxxx/i'
|
| + int firstSlash = qstring.indexOf(QLatin1Char('/'));
|
| + int lastSlash = qstring.lastIndexOf(QLatin1Char('/'));
|
| + if (firstSlash >=0 && lastSlash > firstSlash) {
|
| + QRegExp realRe;
|
| +
|
| + realRe.setPattern(qstring.mid(firstSlash + 1, lastSlash - firstSlash - 1));
|
| +
|
| + if (qstring.mid(lastSlash + 1).contains(QLatin1Char('i')))
|
| + realRe.setCaseSensitivity(Qt::CaseInsensitive);
|
| +
|
| + ret = qVariantFromValue(realRe);
|
| + dist = 0;
|
| + } else {
|
| + qConvDebug() << "couldn't parse a JS regexp";
|
| + }
|
| + } else if (type == String) {
|
| + UString ustring = value.toString(exec);
|
| + QString qstring = QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size());
|
| +
|
| + QRegExp re(qstring);
|
| + if (re.isValid()) {
|
| + ret = qVariantFromValue(re);
|
| + dist = 10;
|
| + }
|
| + }
|
| + break;
|
| +
|
| + case QMetaType::QObjectStar:
|
| + if (type == QObj) {
|
| + QtInstance* qtinst = QtInstance::getInstance(object);
|
| + if (qtinst) {
|
| + if (qtinst->getObject()) {
|
| + qConvDebug() << "found instance, with object:" << (void*) qtinst->getObject();
|
| + ret = qVariantFromValue(qtinst->getObject());
|
| + qConvDebug() << ret;
|
| + dist = 0;
|
| + } else {
|
| + qConvDebug() << "can't convert deleted qobject";
|
| + }
|
| + } else {
|
| + qConvDebug() << "wasn't a qtinstance";
|
| + }
|
| + } else if (type == Null) {
|
| + QObject* nullobj = 0;
|
| + ret = qVariantFromValue(nullobj);
|
| + dist = 0;
|
| + } else {
|
| + qConvDebug() << "previous type was not an object:" << type;
|
| + }
|
| + break;
|
| +
|
| + case QMetaType::VoidStar:
|
| + if (type == QObj) {
|
| + QtInstance* qtinst = QtInstance::getInstance(object);
|
| + if (qtinst) {
|
| + if (qtinst->getObject()) {
|
| + qConvDebug() << "found instance, with object:" << (void*) qtinst->getObject();
|
| + ret = qVariantFromValue((void *)qtinst->getObject());
|
| + qConvDebug() << ret;
|
| + dist = 0;
|
| + } else {
|
| + qConvDebug() << "can't convert deleted qobject";
|
| + }
|
| + } else {
|
| + qConvDebug() << "wasn't a qtinstance";
|
| + }
|
| + } else if (type == Null) {
|
| + ret = qVariantFromValue((void*)0);
|
| + dist = 0;
|
| + } else if (type == Number) {
|
| + // I don't think that converting a double to a pointer is a wise
|
| + // move. Except maybe 0.
|
| + qConvDebug() << "got number for void * - not converting, seems unsafe:" << value.toNumber(exec);
|
| + } else {
|
| + qConvDebug() << "void* - unhandled type" << type;
|
| + }
|
| + break;
|
| +
|
| + default:
|
| + // Non const type ids
|
| + if (hint == (QMetaType::Type) qMetaTypeId<QObjectList>())
|
| + {
|
| + if (type == RTArray) {
|
| + RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
|
| +
|
| + QObjectList result;
|
| + int len = rtarray->getLength();
|
| + for (int i = 0; i < len; ++i) {
|
| + JSValuePtr val = rtarray->getConcreteArray()->valueAt(exec, i);
|
| + int itemdist = -1;
|
| + QVariant item = convertValueToQVariant(exec, val, QMetaType::QObjectStar, &itemdist, visitedObjects);
|
| + if (itemdist >= 0)
|
| + result.append(item.value<QObject*>());
|
| + else
|
| + break;
|
| + }
|
| + // If we didn't fail conversion
|
| + if (result.count() == len) {
|
| + dist = 5;
|
| + ret = QVariant::fromValue(result);
|
| + }
|
| + } else if (type == Array) {
|
| + JSObject* object = value.toObject(exec);
|
| + JSArray* array = static_cast<JSArray *>(object);
|
| + QObjectList result;
|
| + int len = array->length();
|
| + for (int i = 0; i < len; ++i) {
|
| + JSValuePtr val = array->get(exec, i);
|
| + int itemdist = -1;
|
| + QVariant item = convertValueToQVariant(exec, val, QMetaType::QObjectStar, &itemdist, visitedObjects);
|
| + if (itemdist >= 0)
|
| + result.append(item.value<QObject*>());
|
| + else
|
| + break;
|
| + }
|
| + // If we didn't fail conversion
|
| + if (result.count() == len) {
|
| + dist = 5;
|
| + ret = QVariant::fromValue(result);
|
| + }
|
| + } else {
|
| + // Make a single length array
|
| + QObjectList result;
|
| + int itemdist = -1;
|
| + QVariant item = convertValueToQVariant(exec, value, QMetaType::QObjectStar, &itemdist, visitedObjects);
|
| + if (itemdist >= 0) {
|
| + result.append(item.value<QObject*>());
|
| + dist = 10;
|
| + ret = QVariant::fromValue(result);
|
| + }
|
| + }
|
| + break;
|
| + } else if (hint == (QMetaType::Type) qMetaTypeId<QList<int> >()) {
|
| + if (type == RTArray) {
|
| + RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
|
| +
|
| + QList<int> result;
|
| + int len = rtarray->getLength();
|
| + for (int i = 0; i < len; ++i) {
|
| + JSValuePtr val = rtarray->getConcreteArray()->valueAt(exec, i);
|
| + int itemdist = -1;
|
| + QVariant item = convertValueToQVariant(exec, val, QMetaType::Int, &itemdist, visitedObjects);
|
| + if (itemdist >= 0)
|
| + result.append(item.value<int>());
|
| + else
|
| + break;
|
| + }
|
| + // If we didn't fail conversion
|
| + if (result.count() == len) {
|
| + dist = 5;
|
| + ret = QVariant::fromValue(result);
|
| + }
|
| + } else if (type == Array) {
|
| + JSArray* array = static_cast<JSArray *>(object);
|
| +
|
| + QList<int> result;
|
| + int len = array->length();
|
| + for (int i = 0; i < len; ++i) {
|
| + JSValuePtr val = array->get(exec, i);
|
| + int itemdist = -1;
|
| + QVariant item = convertValueToQVariant(exec, val, QMetaType::Int, &itemdist, visitedObjects);
|
| + if (itemdist >= 0)
|
| + result.append(item.value<int>());
|
| + else
|
| + break;
|
| + }
|
| + // If we didn't fail conversion
|
| + if (result.count() == len) {
|
| + dist = 5;
|
| + ret = QVariant::fromValue(result);
|
| + }
|
| + } else {
|
| + // Make a single length array
|
| + QList<int> result;
|
| + int itemdist = -1;
|
| + QVariant item = convertValueToQVariant(exec, value, QMetaType::Int, &itemdist, visitedObjects);
|
| + if (itemdist >= 0) {
|
| + result.append(item.value<int>());
|
| + dist = 10;
|
| + ret = QVariant::fromValue(result);
|
| + }
|
| + }
|
| + break;
|
| + } else if (hint == (QMetaType::Type) qMetaTypeId<QVariant>()) {
|
| + if (value.isUndefinedOrNull()) {
|
| + if (distance)
|
| + *distance = 1;
|
| + return QVariant();
|
| + } else {
|
| + if (type == Object) {
|
| + // Since we haven't really visited this object yet, we remove it
|
| + visitedObjects->remove(object);
|
| + }
|
| +
|
| + // And then recurse with the autodetect flag
|
| + ret = convertValueToQVariant(exec, value, QMetaType::Void, distance, visitedObjects);
|
| + dist = 10;
|
| + }
|
| + break;
|
| + }
|
| +
|
| + dist = 10;
|
| + break;
|
| + }
|
| +
|
| + if (!ret.isValid())
|
| + dist = -1;
|
| + if (distance)
|
| + *distance = dist;
|
| +
|
| + return ret;
|
| +}
|
| +
|
| +QVariant convertValueToQVariant(ExecState* exec, JSValuePtr value, QMetaType::Type hint, int *distance)
|
| +{
|
| + HashSet<JSObject*> visitedObjects;
|
| + return convertValueToQVariant(exec, value, hint, distance, &visitedObjects);
|
| +}
|
| +
|
| +JSValuePtr convertQVariantToValue(ExecState* exec, PassRefPtr<RootObject> root, const QVariant& variant)
|
| +{
|
| + // Variants with QObject * can be isNull but not a null pointer
|
| + // An empty QString variant is also null
|
| + QMetaType::Type type = (QMetaType::Type) variant.userType();
|
| +
|
| + qConvDebug() << "convertQVariantToValue: metatype:" << type << ", isnull: " << variant.isNull();
|
| + if (variant.isNull() &&
|
| + type != QMetaType::QObjectStar &&
|
| + type != QMetaType::VoidStar &&
|
| + type != QMetaType::QWidgetStar &&
|
| + type != QMetaType::QString) {
|
| + return jsNull();
|
| + }
|
| +
|
| + JSLock lock(false);
|
| +
|
| + if (type == QMetaType::Bool)
|
| + return jsBoolean(variant.toBool());
|
| +
|
| + if (type == QMetaType::Int ||
|
| + type == QMetaType::UInt ||
|
| + type == QMetaType::Long ||
|
| + type == QMetaType::ULong ||
|
| + type == QMetaType::LongLong ||
|
| + type == QMetaType::ULongLong ||
|
| + type == QMetaType::Short ||
|
| + type == QMetaType::UShort ||
|
| + type == QMetaType::Float ||
|
| + type == QMetaType::Double)
|
| + return jsNumber(exec, variant.toDouble());
|
| +
|
| + if (type == QMetaType::QRegExp) {
|
| + QRegExp re = variant.value<QRegExp>();
|
| +
|
| + if (re.isValid()) {
|
| + UString uflags;
|
| + if (re.caseSensitivity() == Qt::CaseInsensitive)
|
| + uflags = "i"; // ### Can't do g or m
|
| +
|
| + UString pattern((UChar*)re.pattern().utf16(), re.pattern().length());
|
| +
|
| + RefPtr<JSC::RegExp> regExp = JSC::RegExp::create(&exec->globalData(), pattern, uflags);
|
| + if (regExp->isValid())
|
| + return new (exec) RegExpObject(exec->lexicalGlobalObject()->regExpStructure(), regExp.release());
|
| + else
|
| + return jsNull();
|
| + }
|
| + }
|
| +
|
| + if (type == QMetaType::QDateTime ||
|
| + type == QMetaType::QDate ||
|
| + type == QMetaType::QTime) {
|
| +
|
| + QDate date = QDate::currentDate();
|
| + QTime time(0,0,0); // midnight
|
| +
|
| + if (type == QMetaType::QDate)
|
| + date = variant.value<QDate>();
|
| + else if (type == QMetaType::QTime)
|
| + time = variant.value<QTime>();
|
| + else {
|
| + QDateTime dt = variant.value<QDateTime>().toLocalTime();
|
| + date = dt.date();
|
| + time = dt.time();
|
| + }
|
| +
|
| + // Dates specified this way are in local time (we convert DateTimes above)
|
| + GregorianDateTime dt;
|
| + dt.year = date.year() - 1900;
|
| + dt.month = date.month() - 1;
|
| + dt.monthDay = date.day();
|
| + dt.hour = time.hour();
|
| + dt.minute = time.minute();
|
| + dt.second = time.second();
|
| + dt.isDST = -1;
|
| + double ms = JSC::gregorianDateTimeToMS(dt, time.msec(), /*inputIsUTC*/ false);
|
| +
|
| + DateInstance* instance = new (exec) DateInstance(exec->lexicalGlobalObject()->dateStructure());
|
| + instance->setInternalValue(jsNumber(exec, trunc(ms)));
|
| + return instance;
|
| + }
|
| +
|
| + if (type == QMetaType::QByteArray) {
|
| + QByteArray qtByteArray = variant.value<QByteArray>();
|
| + WTF::RefPtr<WTF::ByteArray> wtfByteArray = WTF::ByteArray::create(qtByteArray.length());
|
| + qMemCopy(wtfByteArray->data(), qtByteArray.constData(), qtByteArray.length());
|
| + return new (exec) JSC::JSByteArray(exec, JSC::JSByteArray::createStructure(jsNull()), wtfByteArray.get());
|
| + }
|
| +
|
| + if (type == QMetaType::QObjectStar || type == QMetaType::QWidgetStar) {
|
| + QObject* obj = variant.value<QObject*>();
|
| + return QtInstance::getQtInstance(obj, root)->createRuntimeObject(exec);
|
| + }
|
| +
|
| + if (type == QMetaType::QVariantMap) {
|
| + // create a new object, and stuff properties into it
|
| + JSObject* ret = constructEmptyObject(exec);
|
| + QVariantMap map = variant.value<QVariantMap>();
|
| + QVariantMap::const_iterator i = map.constBegin();
|
| + while (i != map.constEnd()) {
|
| + QString s = i.key();
|
| + JSValuePtr val = convertQVariantToValue(exec, root, i.value());
|
| + if (val) {
|
| + PutPropertySlot slot;
|
| + ret->put(exec, Identifier(exec, (const UChar *)s.constData(), s.length()), val, slot);
|
| + // ### error case?
|
| + }
|
| + ++i;
|
| + }
|
| +
|
| + return ret;
|
| + }
|
| +
|
| + // List types
|
| + if (type == QMetaType::QVariantList) {
|
| + QVariantList vl = variant.toList();
|
| + qConvDebug() << "got a " << vl.count() << " length list:" << vl;
|
| + return new (exec) RuntimeArray(exec, new QtArray<QVariant>(vl, QMetaType::Void, root));
|
| + } else if (type == QMetaType::QStringList) {
|
| + QStringList sl = variant.value<QStringList>();
|
| + return new (exec) RuntimeArray(exec, new QtArray<QString>(sl, QMetaType::QString, root));
|
| + } else if (type == (QMetaType::Type) qMetaTypeId<QObjectList>()) {
|
| + QObjectList ol= variant.value<QObjectList>();
|
| + return new (exec) RuntimeArray(exec, new QtArray<QObject*>(ol, QMetaType::QObjectStar, root));
|
| + } else if (type == (QMetaType::Type)qMetaTypeId<QList<int> >()) {
|
| + QList<int> il= variant.value<QList<int> >();
|
| + return new (exec) RuntimeArray(exec, new QtArray<int>(il, QMetaType::Int, root));
|
| + }
|
| +
|
| + if (type == (QMetaType::Type)qMetaTypeId<QVariant>()) {
|
| + QVariant real = variant.value<QVariant>();
|
| + qConvDebug() << "real variant is:" << real;
|
| + return convertQVariantToValue(exec, root, real);
|
| + }
|
| +
|
| + qConvDebug() << "fallback path for" << variant << variant.userType();
|
| +
|
| + QString string = variant.toString();
|
| + UString ustring((UChar*)string.utf16(), string.length());
|
| + return jsString(exec, ustring);
|
| +}
|
| +
|
| +// ===============
|
| +
|
| +// Qt-like macros
|
| +#define QW_D(Class) Class##Data* d = d_func()
|
| +#define QW_DS(Class,Instance) Class##Data* d = Instance->d_func()
|
| +
|
| +const ClassInfo QtRuntimeMethod::s_info = { "QtRuntimeMethod", 0, 0, 0 };
|
| +
|
| +QtRuntimeMethod::QtRuntimeMethod(QtRuntimeMethodData* dd, ExecState* exec, const Identifier& ident, PassRefPtr<QtInstance> inst)
|
| + : InternalFunction(&exec->globalData(), getDOMStructure<QtRuntimeMethod>(exec), ident)
|
| + , d_ptr(dd)
|
| +{
|
| + QW_D(QtRuntimeMethod);
|
| + d->m_instance = inst;
|
| +}
|
| +
|
| +QtRuntimeMethod::~QtRuntimeMethod()
|
| +{
|
| + delete d_ptr;
|
| +}
|
| +
|
| +// ===============
|
| +
|
| +QtRuntimeMethodData::~QtRuntimeMethodData()
|
| +{
|
| +}
|
| +
|
| +QtRuntimeMetaMethodData::~QtRuntimeMetaMethodData()
|
| +{
|
| +
|
| +}
|
| +
|
| +QtRuntimeConnectionMethodData::~QtRuntimeConnectionMethodData()
|
| +{
|
| +
|
| +}
|
| +
|
| +// ===============
|
| +
|
| +// Type conversion metadata (from QtScript originally)
|
| +class QtMethodMatchType
|
| +{
|
| +public:
|
| + enum Kind {
|
| + Invalid,
|
| + Variant,
|
| + MetaType,
|
| + Unresolved,
|
| + MetaEnum
|
| + };
|
| +
|
| +
|
| + QtMethodMatchType()
|
| + : m_kind(Invalid) { }
|
| +
|
| + Kind kind() const
|
| + { return m_kind; }
|
| +
|
| + QMetaType::Type typeId() const;
|
| +
|
| + bool isValid() const
|
| + { return (m_kind != Invalid); }
|
| +
|
| + bool isVariant() const
|
| + { return (m_kind == Variant); }
|
| +
|
| + bool isMetaType() const
|
| + { return (m_kind == MetaType); }
|
| +
|
| + bool isUnresolved() const
|
| + { return (m_kind == Unresolved); }
|
| +
|
| + bool isMetaEnum() const
|
| + { return (m_kind == MetaEnum); }
|
| +
|
| + QByteArray name() const;
|
| +
|
| + int enumeratorIndex() const
|
| + { Q_ASSERT(isMetaEnum()); return m_typeId; }
|
| +
|
| + static QtMethodMatchType variant()
|
| + { return QtMethodMatchType(Variant); }
|
| +
|
| + static QtMethodMatchType metaType(int typeId, const QByteArray &name)
|
| + { return QtMethodMatchType(MetaType, typeId, name); }
|
| +
|
| + static QtMethodMatchType metaEnum(int enumIndex, const QByteArray &name)
|
| + { return QtMethodMatchType(MetaEnum, enumIndex, name); }
|
| +
|
| + static QtMethodMatchType unresolved(const QByteArray &name)
|
| + { return QtMethodMatchType(Unresolved, /*typeId=*/0, name); }
|
| +
|
| +private:
|
| + QtMethodMatchType(Kind kind, int typeId = 0, const QByteArray &name = QByteArray())
|
| + : m_kind(kind), m_typeId(typeId), m_name(name) { }
|
| +
|
| + Kind m_kind;
|
| + int m_typeId;
|
| + QByteArray m_name;
|
| +};
|
| +
|
| +QMetaType::Type QtMethodMatchType::typeId() const
|
| +{
|
| + if (isVariant())
|
| + return (QMetaType::Type) QMetaType::type("QVariant");
|
| + return (QMetaType::Type) (isMetaEnum() ? QMetaType::Int : m_typeId);
|
| +}
|
| +
|
| +QByteArray QtMethodMatchType::name() const
|
| +{
|
| + if (!m_name.isEmpty())
|
| + return m_name;
|
| + else if (m_kind == Variant)
|
| + return "QVariant";
|
| + return QByteArray();
|
| +}
|
| +
|
| +struct QtMethodMatchData
|
| +{
|
| + int matchDistance;
|
| + int index;
|
| + QVector<QtMethodMatchType> types;
|
| + QVarLengthArray<QVariant, 10> args;
|
| +
|
| + QtMethodMatchData(int dist, int idx, QVector<QtMethodMatchType> typs,
|
| + const QVarLengthArray<QVariant, 10> &as)
|
| + : matchDistance(dist), index(idx), types(typs), args(as) { }
|
| + QtMethodMatchData()
|
| + : index(-1) { }
|
| +
|
| + bool isValid() const
|
| + { return (index != -1); }
|
| +
|
| + int firstUnresolvedIndex() const
|
| + {
|
| + for (int i=0; i < types.count(); i++) {
|
| + if (types.at(i).isUnresolved())
|
| + return i;
|
| + }
|
| + return -1;
|
| + }
|
| +};
|
| +
|
| +static int indexOfMetaEnum(const QMetaObject *meta, const QByteArray &str)
|
| +{
|
| + QByteArray scope;
|
| + QByteArray name;
|
| + int scopeIdx = str.indexOf("::");
|
| + if (scopeIdx != -1) {
|
| + scope = str.left(scopeIdx);
|
| + name = str.mid(scopeIdx + 2);
|
| + } else {
|
| + name = str;
|
| + }
|
| + for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
|
| + QMetaEnum m = meta->enumerator(i);
|
| + if ((m.name() == name)/* && (scope.isEmpty() || (m.scope() == scope))*/)
|
| + return i;
|
| + }
|
| + return -1;
|
| +}
|
| +
|
| +// Helper function for resolving methods
|
| +// Largely based on code in QtScript for compatibility reasons
|
| +static int findMethodIndex(ExecState* exec,
|
| + const QMetaObject* meta,
|
| + const QByteArray& signature,
|
| + bool allowPrivate,
|
| + const ArgList& jsArgs,
|
| + QVarLengthArray<QVariant, 10> &vars,
|
| + void** vvars,
|
| + JSObject **pError)
|
| +{
|
| + QList<int> matchingIndices;
|
| +
|
| + bool overloads = !signature.contains('(');
|
| +
|
| + int count = meta->methodCount();
|
| + for (int i = count - 1; i >= 0; --i) {
|
| + const QMetaMethod m = meta->method(i);
|
| +
|
| + // Don't choose private methods
|
| + if (m.access() == QMetaMethod::Private && !allowPrivate)
|
| + continue;
|
| +
|
| + // try and find all matching named methods
|
| + if (m.signature() == signature)
|
| + matchingIndices.append(i);
|
| + else if (overloads) {
|
| + QByteArray rawsignature = m.signature();
|
| + rawsignature.truncate(rawsignature.indexOf('('));
|
| + if (rawsignature == signature)
|
| + matchingIndices.append(i);
|
| + }
|
| + }
|
| +
|
| + int chosenIndex = -1;
|
| + *pError = 0;
|
| + QVector<QtMethodMatchType> chosenTypes;
|
| +
|
| + QVarLengthArray<QVariant, 10> args;
|
| + QVector<QtMethodMatchData> candidates;
|
| + QVector<QtMethodMatchData> unresolved;
|
| + QVector<int> tooFewArgs;
|
| + QVector<int> conversionFailed;
|
| +
|
| + foreach(int index, matchingIndices) {
|
| + QMetaMethod method = meta->method(index);
|
| +
|
| + QVector<QtMethodMatchType> types;
|
| + bool unresolvedTypes = false;
|
| +
|
| + // resolve return type
|
| + QByteArray returnTypeName = method.typeName();
|
| + int rtype = QMetaType::type(returnTypeName);
|
| + if ((rtype == 0) && !returnTypeName.isEmpty()) {
|
| + if (returnTypeName == "QVariant") {
|
| + types.append(QtMethodMatchType::variant());
|
| + } else if (returnTypeName.endsWith('*')) {
|
| + types.append(QtMethodMatchType::metaType(QMetaType::VoidStar, returnTypeName));
|
| + } else {
|
| + int enumIndex = indexOfMetaEnum(meta, returnTypeName);
|
| + if (enumIndex != -1)
|
| + types.append(QtMethodMatchType::metaEnum(enumIndex, returnTypeName));
|
| + else {
|
| + unresolvedTypes = true;
|
| + types.append(QtMethodMatchType::unresolved(returnTypeName));
|
| + }
|
| + }
|
| + } else {
|
| + if (returnTypeName == "QVariant")
|
| + types.append(QtMethodMatchType::variant());
|
| + else
|
| + types.append(QtMethodMatchType::metaType(rtype, returnTypeName));
|
| + }
|
| +
|
| + // resolve argument types
|
| + QList<QByteArray> parameterTypeNames = method.parameterTypes();
|
| + for (int i = 0; i < parameterTypeNames.count(); ++i) {
|
| + QByteArray argTypeName = parameterTypeNames.at(i);
|
| + int atype = QMetaType::type(argTypeName);
|
| + if (atype == 0) {
|
| + if (argTypeName == "QVariant") {
|
| + types.append(QtMethodMatchType::variant());
|
| + } else {
|
| + int enumIndex = indexOfMetaEnum(meta, argTypeName);
|
| + if (enumIndex != -1)
|
| + types.append(QtMethodMatchType::metaEnum(enumIndex, argTypeName));
|
| + else {
|
| + unresolvedTypes = true;
|
| + types.append(QtMethodMatchType::unresolved(argTypeName));
|
| + }
|
| + }
|
| + } else {
|
| + if (argTypeName == "QVariant")
|
| + types.append(QtMethodMatchType::variant());
|
| + else
|
| + types.append(QtMethodMatchType::metaType(atype, argTypeName));
|
| + }
|
| + }
|
| +
|
| + // If the native method requires more arguments than what was passed from JavaScript
|
| + if (jsArgs.size() < (types.count() - 1)) {
|
| + qMatchDebug() << "Match:too few args for" << method.signature();
|
| + tooFewArgs.append(index);
|
| + continue;
|
| + }
|
| +
|
| + if (unresolvedTypes) {
|
| + qMatchDebug() << "Match:unresolved arg types for" << method.signature();
|
| + // remember it so we can give an error message later, if necessary
|
| + unresolved.append(QtMethodMatchData(/*matchDistance=*/INT_MAX, index,
|
| + types, QVarLengthArray<QVariant, 10>()));
|
| + continue;
|
| + }
|
| +
|
| + // Now convert arguments
|
| + if (args.count() != types.count())
|
| + args.resize(types.count());
|
| +
|
| + QtMethodMatchType retType = types[0];
|
| + args[0] = QVariant(retType.typeId(), (void *)0); // the return value
|
| +
|
| + bool converted = true;
|
| + int matchDistance = 0;
|
| + for (int i = 0; converted && i < types.count() - 1; ++i) {
|
| + JSValuePtr arg = i < jsArgs.size() ? jsArgs.at(exec, i) : jsUndefined();
|
| +
|
| + int argdistance = -1;
|
| + QVariant v = convertValueToQVariant(exec, arg, types.at(i+1).typeId(), &argdistance);
|
| + if (argdistance >= 0) {
|
| + matchDistance += argdistance;
|
| + args[i+1] = v;
|
| + } else {
|
| + qMatchDebug() << "failed to convert argument " << i << "type" << types.at(i+1).typeId() << QMetaType::typeName(types.at(i+1).typeId());
|
| + converted = false;
|
| + }
|
| + }
|
| +
|
| + qMatchDebug() << "Match: " << method.signature() << (converted ? "converted":"failed to convert") << "distance " << matchDistance;
|
| +
|
| + if (converted) {
|
| + if ((jsArgs.size() == types.count() - 1)
|
| + && (matchDistance == 0)) {
|
| + // perfect match, use this one
|
| + chosenIndex = index;
|
| + break;
|
| + } else {
|
| + QtMethodMatchData currentMatch(matchDistance, index, types, args);
|
| + if (candidates.isEmpty()) {
|
| + candidates.append(currentMatch);
|
| + } else {
|
| + QtMethodMatchData bestMatchSoFar = candidates.at(0);
|
| + if ((args.count() > bestMatchSoFar.args.count())
|
| + || ((args.count() == bestMatchSoFar.args.count())
|
| + && (matchDistance <= bestMatchSoFar.matchDistance))) {
|
| + candidates.prepend(currentMatch);
|
| + } else {
|
| + candidates.append(currentMatch);
|
| + }
|
| + }
|
| + }
|
| + } else {
|
| + conversionFailed.append(index);
|
| + }
|
| +
|
| + if (!overloads)
|
| + break;
|
| + }
|
| +
|
| + if (chosenIndex == -1 && candidates.count() == 0) {
|
| + // No valid functions at all - format an error message
|
| + if (!conversionFailed.isEmpty()) {
|
| + QString message = QString::fromLatin1("incompatible type of argument(s) in call to %0(); candidates were\n")
|
| + .arg(QLatin1String(signature));
|
| + for (int i = 0; i < conversionFailed.size(); ++i) {
|
| + if (i > 0)
|
| + message += QLatin1String("\n");
|
| + QMetaMethod mtd = meta->method(conversionFailed.at(i));
|
| + message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
|
| + }
|
| + *pError = throwError(exec, TypeError, message.toLatin1().constData());
|
| + } else if (!unresolved.isEmpty()) {
|
| + QtMethodMatchData argsInstance = unresolved.first();
|
| + int unresolvedIndex = argsInstance.firstUnresolvedIndex();
|
| + Q_ASSERT(unresolvedIndex != -1);
|
| + QtMethodMatchType unresolvedType = argsInstance.types.at(unresolvedIndex);
|
| + QString message = QString::fromLatin1("cannot call %0(): unknown type `%1'")
|
| + .arg(QString::fromLatin1(signature))
|
| + .arg(QLatin1String(unresolvedType.name()));
|
| + *pError = throwError(exec, TypeError, message.toLatin1().constData());
|
| + } else {
|
| + QString message = QString::fromLatin1("too few arguments in call to %0(); candidates are\n")
|
| + .arg(QLatin1String(signature));
|
| + for (int i = 0; i < tooFewArgs.size(); ++i) {
|
| + if (i > 0)
|
| + message += QLatin1String("\n");
|
| + QMetaMethod mtd = meta->method(tooFewArgs.at(i));
|
| + message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
|
| + }
|
| + *pError = throwError(exec, SyntaxError, message.toLatin1().constData());
|
| + }
|
| + }
|
| +
|
| + if (chosenIndex == -1 && candidates.count() > 0) {
|
| + QtMethodMatchData bestMatch = candidates.at(0);
|
| + if ((candidates.size() > 1)
|
| + && (bestMatch.args.count() == candidates.at(1).args.count())
|
| + && (bestMatch.matchDistance == candidates.at(1).matchDistance)) {
|
| + // ambiguous call
|
| + QString message = QString::fromLatin1("ambiguous call of overloaded function %0(); candidates were\n")
|
| + .arg(QLatin1String(signature));
|
| + for (int i = 0; i < candidates.size(); ++i) {
|
| + // Only candidate for overload if argument count and match distance is same as best match
|
| + if (candidates.at(i).args.count() == bestMatch.args.count()
|
| + || candidates.at(i).matchDistance == bestMatch.matchDistance) {
|
| + if (i > 0)
|
| + message += QLatin1String("\n");
|
| + QMetaMethod mtd = meta->method(candidates.at(i).index);
|
| + message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
|
| + }
|
| + }
|
| + *pError = throwError(exec, TypeError, message.toLatin1().constData());
|
| + } else {
|
| + chosenIndex = bestMatch.index;
|
| + args = bestMatch.args;
|
| + }
|
| + }
|
| +
|
| + if (chosenIndex != -1) {
|
| + /* Copy the stuff over */
|
| + int i;
|
| + vars.resize(args.count());
|
| + for (i=0; i < args.count(); i++) {
|
| + vars[i] = args[i];
|
| + vvars[i] = vars[i].data();
|
| + }
|
| + }
|
| +
|
| + return chosenIndex;
|
| +}
|
| +
|
| +// Signals are not fuzzy matched as much as methods
|
| +static int findSignalIndex(const QMetaObject* meta, int initialIndex, QByteArray signature)
|
| +{
|
| + int index = initialIndex;
|
| + QMetaMethod method = meta->method(index);
|
| + bool overloads = !signature.contains('(');
|
| + if (overloads && (method.attributes() & QMetaMethod::Cloned)) {
|
| + // find the most general method
|
| + do {
|
| + method = meta->method(--index);
|
| + } while (method.attributes() & QMetaMethod::Cloned);
|
| + }
|
| + return index;
|
| +}
|
| +
|
| +QtRuntimeMetaMethod::QtRuntimeMetaMethod(ExecState* exec, const Identifier& ident, PassRefPtr<QtInstance> inst, int index, const QByteArray& signature, bool allowPrivate)
|
| + : QtRuntimeMethod (new QtRuntimeMetaMethodData(), exec, ident, inst)
|
| +{
|
| + QW_D(QtRuntimeMetaMethod);
|
| + d->m_signature = signature;
|
| + d->m_index = index;
|
| + d->m_connect = 0;
|
| + d->m_disconnect = 0;
|
| + d->m_allowPrivate = allowPrivate;
|
| +}
|
| +
|
| +void QtRuntimeMetaMethod::mark()
|
| +{
|
| + QtRuntimeMethod::mark();
|
| + QW_D(QtRuntimeMetaMethod);
|
| + if (d->m_connect)
|
| + d->m_connect->mark();
|
| + if (d->m_disconnect)
|
| + d->m_disconnect->mark();
|
| +}
|
| +
|
| +JSValuePtr QtRuntimeMetaMethod::call(ExecState* exec, JSObject* functionObject, JSValuePtr thisValue, const ArgList& args)
|
| +{
|
| + QtRuntimeMetaMethodData* d = static_cast<QtRuntimeMetaMethod *>(functionObject)->d_func();
|
| +
|
| + // We're limited to 10 args
|
| + if (args.size() > 10)
|
| + return jsUndefined();
|
| +
|
| + // We have to pick a method that matches..
|
| + JSLock lock(false);
|
| +
|
| + QObject *obj = d->m_instance->getObject();
|
| + if (obj) {
|
| + QVarLengthArray<QVariant, 10> vargs;
|
| + void *qargs[11];
|
| +
|
| + int methodIndex;
|
| + JSObject* errorObj = 0;
|
| + if ((methodIndex = findMethodIndex(exec, obj->metaObject(), d->m_signature, d->m_allowPrivate, args, vargs, (void **)qargs, &errorObj)) != -1) {
|
| + if (obj->qt_metacall(QMetaObject::InvokeMetaMethod, methodIndex, qargs) >= 0)
|
| + return jsUndefined();
|
| +
|
| + if (vargs[0].isValid())
|
| + return convertQVariantToValue(exec, d->m_instance->rootObject(), vargs[0]);
|
| + }
|
| +
|
| + if (errorObj)
|
| + return errorObj;
|
| + } else {
|
| + return throwError(exec, GeneralError, "cannot call function of deleted QObject");
|
| + }
|
| +
|
| + // void functions return undefined
|
| + return jsUndefined();
|
| +}
|
| +
|
| +CallType QtRuntimeMetaMethod::getCallData(CallData& callData)
|
| +{
|
| + callData.native.function = call;
|
| + return CallTypeHost;
|
| +}
|
| +
|
| +bool QtRuntimeMetaMethod::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
|
| +{
|
| + if (propertyName == "connect") {
|
| + slot.setCustom(this, connectGetter);
|
| + return true;
|
| + } else if (propertyName == "disconnect") {
|
| + slot.setCustom(this, disconnectGetter);
|
| + return true;
|
| + } else if (propertyName == exec->propertyNames().length) {
|
| + slot.setCustom(this, lengthGetter);
|
| + return true;
|
| + }
|
| +
|
| + return QtRuntimeMethod::getOwnPropertySlot(exec, propertyName, slot);
|
| +}
|
| +
|
| +JSValuePtr QtRuntimeMetaMethod::lengthGetter(ExecState* exec, const Identifier&, const PropertySlot&)
|
| +{
|
| + // QtScript always returns 0
|
| + return jsNumber(exec, 0);
|
| +}
|
| +
|
| +JSValuePtr QtRuntimeMetaMethod::connectGetter(ExecState* exec, const Identifier& ident, const PropertySlot& slot)
|
| +{
|
| + QtRuntimeMetaMethod* thisObj = static_cast<QtRuntimeMetaMethod*>(asObject(slot.slotBase()));
|
| + QW_DS(QtRuntimeMetaMethod, thisObj);
|
| +
|
| + if (!d->m_connect)
|
| + d->m_connect = new (exec) QtRuntimeConnectionMethod(exec, ident, true, d->m_instance, d->m_index, d->m_signature);
|
| + return d->m_connect;
|
| +}
|
| +
|
| +JSValuePtr QtRuntimeMetaMethod::disconnectGetter(ExecState* exec, const Identifier& ident, const PropertySlot& slot)
|
| +{
|
| + QtRuntimeMetaMethod* thisObj = static_cast<QtRuntimeMetaMethod*>(asObject(slot.slotBase()));
|
| + QW_DS(QtRuntimeMetaMethod, thisObj);
|
| +
|
| + if (!d->m_disconnect)
|
| + d->m_disconnect = new (exec) QtRuntimeConnectionMethod(exec, ident, false, d->m_instance, d->m_index, d->m_signature);
|
| + return d->m_disconnect;
|
| +}
|
| +
|
| +// ===============
|
| +
|
| +QMultiMap<QObject*, QtConnectionObject*> QtRuntimeConnectionMethod::connections;
|
| +
|
| +QtRuntimeConnectionMethod::QtRuntimeConnectionMethod(ExecState* exec, const Identifier& ident, bool isConnect, PassRefPtr<QtInstance> inst, int index, const QByteArray& signature)
|
| + : QtRuntimeMethod (new QtRuntimeConnectionMethodData(), exec, ident, inst)
|
| +{
|
| + QW_D(QtRuntimeConnectionMethod);
|
| +
|
| + d->m_signature = signature;
|
| + d->m_index = index;
|
| + d->m_isConnect = isConnect;
|
| +}
|
| +
|
| +JSValuePtr QtRuntimeConnectionMethod::call(ExecState* exec, JSObject* functionObject, JSValuePtr thisValue, const ArgList& args)
|
| +{
|
| + QtRuntimeConnectionMethodData* d = static_cast<QtRuntimeConnectionMethod *>(functionObject)->d_func();
|
| +
|
| + JSLock lock(false);
|
| +
|
| + QObject* sender = d->m_instance->getObject();
|
| +
|
| + if (sender) {
|
| +
|
| + JSObject* thisObject = exec->lexicalGlobalObject();
|
| + JSObject* funcObject = 0;
|
| +
|
| + // QtScript checks signalness first, arguments second
|
| + int signalIndex = -1;
|
| +
|
| + // Make sure the initial index is a signal
|
| + QMetaMethod m = sender->metaObject()->method(d->m_index);
|
| + if (m.methodType() == QMetaMethod::Signal)
|
| + signalIndex = findSignalIndex(sender->metaObject(), d->m_index, d->m_signature);
|
| +
|
| + if (signalIndex != -1) {
|
| + if (args.size() == 1) {
|
| + funcObject = args.at(exec, 0).toObject(exec);
|
| + CallData callData;
|
| + if (funcObject->getCallData(callData) == CallTypeNone) {
|
| + if (d->m_isConnect)
|
| + return throwError(exec, TypeError, "QtMetaMethod.connect: target is not a function");
|
| + else
|
| + return throwError(exec, TypeError, "QtMetaMethod.disconnect: target is not a function");
|
| + }
|
| + } else if (args.size() >= 2) {
|
| + if (args.at(exec, 0).isObject()) {
|
| + thisObject = args.at(exec, 0).toObject(exec);
|
| +
|
| + // Get the actual function to call
|
| + JSObject *asObj = args.at(exec, 1).toObject(exec);
|
| + CallData callData;
|
| + if (asObj->getCallData(callData) != CallTypeNone) {
|
| + // Function version
|
| + funcObject = asObj;
|
| + } else {
|
| + // Convert it to a string
|
| + UString funcName = args.at(exec, 1).toString(exec);
|
| + Identifier funcIdent(exec, funcName);
|
| +
|
| + // ### DropAllLocks
|
| + // This is resolved at this point in QtScript
|
| + JSValuePtr val = thisObject->get(exec, funcIdent);
|
| + JSObject* asFuncObj = val.toObject(exec);
|
| +
|
| + if (asFuncObj->getCallData(callData) != CallTypeNone) {
|
| + funcObject = asFuncObj;
|
| + } else {
|
| + if (d->m_isConnect)
|
| + return throwError(exec, TypeError, "QtMetaMethod.connect: target is not a function");
|
| + else
|
| + return throwError(exec, TypeError, "QtMetaMethod.disconnect: target is not a function");
|
| + }
|
| + }
|
| + } else {
|
| + if (d->m_isConnect)
|
| + return throwError(exec, TypeError, "QtMetaMethod.connect: thisObject is not an object");
|
| + else
|
| + return throwError(exec, TypeError, "QtMetaMethod.disconnect: thisObject is not an object");
|
| + }
|
| + } else {
|
| + if (d->m_isConnect)
|
| + return throwError(exec, GeneralError, "QtMetaMethod.connect: no arguments given");
|
| + else
|
| + return throwError(exec, GeneralError, "QtMetaMethod.disconnect: no arguments given");
|
| + }
|
| +
|
| + if (d->m_isConnect) {
|
| + // to connect, we need:
|
| + // target object [from ctor]
|
| + // target signal index etc. [from ctor]
|
| + // receiver function [from arguments]
|
| + // receiver this object [from arguments]
|
| +
|
| + QtConnectionObject* conn = new QtConnectionObject(d->m_instance, signalIndex, thisObject, funcObject);
|
| + bool ok = QMetaObject::connect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
|
| + if (!ok) {
|
| + delete conn;
|
| + QString msg = QString(QLatin1String("QtMetaMethod.connect: failed to connect to %1::%2()"))
|
| + .arg(QLatin1String(sender->metaObject()->className()))
|
| + .arg(QLatin1String(d->m_signature));
|
| + return throwError(exec, GeneralError, msg.toLatin1().constData());
|
| + }
|
| + else {
|
| + // Store connection
|
| + connections.insert(sender, conn);
|
| + }
|
| + } else {
|
| + // Now to find our previous connection object. Hmm.
|
| + QList<QtConnectionObject*> conns = connections.values(sender);
|
| + bool ret = false;
|
| +
|
| + foreach(QtConnectionObject* conn, conns) {
|
| + // Is this the right connection?
|
| + if (conn->match(sender, signalIndex, thisObject, funcObject)) {
|
| + // Yep, disconnect it
|
| + QMetaObject::disconnect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
|
| + delete conn; // this will also remove it from the map
|
| + ret = true;
|
| + break;
|
| + }
|
| + }
|
| +
|
| + if (!ret) {
|
| + QString msg = QString(QLatin1String("QtMetaMethod.disconnect: failed to disconnect from %1::%2()"))
|
| + .arg(QLatin1String(sender->metaObject()->className()))
|
| + .arg(QLatin1String(d->m_signature));
|
| + return throwError(exec, GeneralError, msg.toLatin1().constData());
|
| + }
|
| + }
|
| + } else {
|
| + QString msg = QString(QLatin1String("QtMetaMethod.%1: %2::%3() is not a signal"))
|
| + .arg(QLatin1String(d->m_isConnect ? "connect": "disconnect"))
|
| + .arg(QLatin1String(sender->metaObject()->className()))
|
| + .arg(QLatin1String(d->m_signature));
|
| + return throwError(exec, TypeError, msg.toLatin1().constData());
|
| + }
|
| + } else {
|
| + return throwError(exec, GeneralError, "cannot call function of deleted QObject");
|
| + }
|
| +
|
| + return jsUndefined();
|
| +}
|
| +
|
| +CallType QtRuntimeConnectionMethod::getCallData(CallData& callData)
|
| +{
|
| + callData.native.function = call;
|
| + return CallTypeHost;
|
| +}
|
| +
|
| +bool QtRuntimeConnectionMethod::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
|
| +{
|
| + if (propertyName == exec->propertyNames().length) {
|
| + slot.setCustom(this, lengthGetter);
|
| + return true;
|
| + }
|
| +
|
| + return QtRuntimeMethod::getOwnPropertySlot(exec, propertyName, slot);
|
| +}
|
| +
|
| +JSValuePtr QtRuntimeConnectionMethod::lengthGetter(ExecState* exec, const Identifier&, const PropertySlot&)
|
| +{
|
| + // we have one formal argument, and one optional
|
| + return jsNumber(exec, 1);
|
| +}
|
| +
|
| +// ===============
|
| +
|
| +QtConnectionObject::QtConnectionObject(PassRefPtr<QtInstance> instance, int signalIndex, JSObject* thisObject, JSObject* funcObject)
|
| + : m_instance(instance)
|
| + , m_signalIndex(signalIndex)
|
| + , m_originalObject(m_instance->getObject())
|
| + , m_thisObject(thisObject)
|
| + , m_funcObject(funcObject)
|
| +{
|
| + setParent(m_originalObject);
|
| + ASSERT(JSLock::currentThreadIsHoldingLock()); // so our ProtectedPtrs are safe
|
| +}
|
| +
|
| +QtConnectionObject::~QtConnectionObject()
|
| +{
|
| + // Remove us from the map of active connections
|
| + QtRuntimeConnectionMethod::connections.remove(m_originalObject, this);
|
| +}
|
| +
|
| +static const uint qt_meta_data_QtConnectionObject[] = {
|
| +
|
| + // content:
|
| + 1, // revision
|
| + 0, // classname
|
| + 0, 0, // classinfo
|
| + 1, 10, // methods
|
| + 0, 0, // properties
|
| + 0, 0, // enums/sets
|
| +
|
| + // slots: signature, parameters, type, tag, flags
|
| + 28, 27, 27, 27, 0x0a,
|
| +
|
| + 0 // eod
|
| +};
|
| +
|
| +static const char qt_meta_stringdata_QtConnectionObject[] = {
|
| + "JSC::Bindings::QtConnectionObject\0\0execute()\0"
|
| +};
|
| +
|
| +const QMetaObject QtConnectionObject::staticMetaObject = {
|
| + { &QObject::staticMetaObject, qt_meta_stringdata_QtConnectionObject,
|
| + qt_meta_data_QtConnectionObject, 0 }
|
| +};
|
| +
|
| +const QMetaObject *QtConnectionObject::metaObject() const
|
| +{
|
| + return &staticMetaObject;
|
| +}
|
| +
|
| +void *QtConnectionObject::qt_metacast(const char *_clname)
|
| +{
|
| + if (!_clname) return 0;
|
| + if (!strcmp(_clname, qt_meta_stringdata_QtConnectionObject))
|
| + return static_cast<void*>(const_cast<QtConnectionObject*>(this));
|
| + return QObject::qt_metacast(_clname);
|
| +}
|
| +
|
| +int QtConnectionObject::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
|
| +{
|
| + _id = QObject::qt_metacall(_c, _id, _a);
|
| + if (_id < 0)
|
| + return _id;
|
| + if (_c == QMetaObject::InvokeMetaMethod) {
|
| + switch (_id) {
|
| + case 0: execute(_a); break;
|
| + }
|
| + _id -= 1;
|
| + }
|
| + return _id;
|
| +}
|
| +
|
| +void QtConnectionObject::execute(void **argv)
|
| +{
|
| + QObject* obj = m_instance->getObject();
|
| + if (obj) {
|
| + const QMetaObject* meta = obj->metaObject();
|
| + const QMetaMethod method = meta->method(m_signalIndex);
|
| +
|
| + QList<QByteArray> parameterTypes = method.parameterTypes();
|
| +
|
| + int argc = parameterTypes.count();
|
| +
|
| + JSLock lock(false);
|
| +
|
| + // ### Should the Interpreter/ExecState come from somewhere else?
|
| + RefPtr<RootObject> ro = m_instance->rootObject();
|
| + if (ro) {
|
| + JSGlobalObject* globalobj = ro->globalObject();
|
| + if (globalobj) {
|
| + ExecState* exec = globalobj->globalExec();
|
| + if (exec) {
|
| + // Build the argument list (up to the formal argument length of the slot)
|
| + ArgList l;
|
| + // ### DropAllLocks?
|
| + int funcArgC = m_funcObject->get(exec, exec->propertyNames().length).toInt32(exec);
|
| + int argTotal = qMax(funcArgC, argc);
|
| + for(int i=0; i < argTotal; i++) {
|
| + if (i < argc) {
|
| + int argType = QMetaType::type(parameterTypes.at(i));
|
| + l.append(convertQVariantToValue(exec, ro, QVariant(argType, argv[i+1])));
|
| + } else {
|
| + l.append(jsUndefined());
|
| + }
|
| + }
|
| + CallData callData;
|
| + CallType callType = m_funcObject->getCallData(callData);
|
| + // Stuff in the __qt_sender property, if we can
|
| + if (m_funcObject->inherits(&JSFunction::info)) {
|
| + JSFunction* fimp = static_cast<JSFunction*>(m_funcObject.get());
|
| +
|
| + JSObject* qt_sender = QtInstance::getQtInstance(sender(), ro)->createRuntimeObject(exec);
|
| + JSObject* wrapper = new (exec) JSObject(JSObject::createStructure(jsNull()));
|
| + PutPropertySlot slot;
|
| + wrapper->put(exec, Identifier(exec, "__qt_sender__"), qt_sender, slot);
|
| + ScopeChain oldsc = fimp->scope();
|
| + ScopeChain sc = oldsc;
|
| + sc.push(wrapper);
|
| + fimp->setScope(sc);
|
| +
|
| + call(exec, fimp, callType, callData, m_thisObject, l);
|
| + fimp->setScope(oldsc);
|
| + } else {
|
| + call(exec, m_funcObject, callType, callData, m_thisObject, l);
|
| + }
|
| + }
|
| + }
|
| + }
|
| + } else {
|
| + // A strange place to be - a deleted object emitted a signal here.
|
| + qWarning() << "sender deleted, cannot deliver signal";
|
| + }
|
| +}
|
| +
|
| +bool QtConnectionObject::match(QObject* sender, int signalIndex, JSObject* thisObject, JSObject *funcObject)
|
| +{
|
| + if (m_originalObject == sender && m_signalIndex == signalIndex
|
| + && thisObject == (JSObject*)m_thisObject && funcObject == (JSObject*)m_funcObject)
|
| + return true;
|
| + return false;
|
| +}
|
| +
|
| +// ===============
|
| +
|
| +template <typename T> QtArray<T>::QtArray(QList<T> list, QMetaType::Type type, PassRefPtr<RootObject> rootObject)
|
| + : Array(rootObject)
|
| + , m_list(list)
|
| + , m_type(type)
|
| +{
|
| + m_length = m_list.count();
|
| +}
|
| +
|
| +template <typename T> QtArray<T>::~QtArray ()
|
| +{
|
| +}
|
| +
|
| +template <typename T> RootObject* QtArray<T>::rootObject() const
|
| +{
|
| + return _rootObject && _rootObject->isValid() ? _rootObject.get() : 0;
|
| +}
|
| +
|
| +template <typename T> void QtArray<T>::setValueAt(ExecState* exec, unsigned index, JSValuePtr aValue) const
|
| +{
|
| + // QtScript sets the value, but doesn't forward it to the original source
|
| + // (e.g. if you do 'object.intList[5] = 6', the object is not updated, but the
|
| + // copy of the list is).
|
| + int dist = -1;
|
| + QVariant val = convertValueToQVariant(exec, aValue, m_type, &dist);
|
| +
|
| + if (dist >= 0) {
|
| + m_list[index] = val.value<T>();
|
| + }
|
| +}
|
| +
|
| +
|
| +template <typename T> JSValuePtr QtArray<T>::valueAt(ExecState *exec, unsigned int index) const
|
| +{
|
| + if (index < m_length) {
|
| + T val = m_list.at(index);
|
| + return convertQVariantToValue(exec, rootObject(), QVariant::fromValue(val));
|
| + }
|
| +
|
| + return jsUndefined();
|
| +}
|
| +
|
| +// ===============
|
| +
|
| +} }
|
| +
|
|
|