QV4::QObjectWrapper: Clean up CallArgument

Prefer comparison of metatypes by type rather than ID. When still
comparing by ID take advantage of switching through the builtin types.
Furthermore, restructure the code for more clarity and consistently
apply the qml_sequence_type guards.

Change-Id: I7572ba644621ac551ae1821a59229b60c1485a1d
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Ulf Hermann 2021-11-09 11:15:04 +01:00
parent cdd8fc015f
commit 3b0125f5ec
1 changed files with 332 additions and 267 deletions

View File

@ -505,7 +505,8 @@ void QObjectWrapper::setProperty(
return false;
}
}();
if (!isAliasToAllowed && !property->isVarProperty() && property->propType().id() != qMetaTypeId<QJSValue>()) {
if (!isAliasToAllowed && !property->isVarProperty()
&& property->propType() != QMetaType::fromType<QJSValue>()) {
// assigning a JS function to a non var or QJSValue property or is not allowed.
QString error = QLatin1String("Cannot assign JavaScript function to ");
if (!QMetaType(property->propType()).name())
@ -586,44 +587,45 @@ void QObjectWrapper::setProperty(
void *argv[] = { &o, 0, &status, &flags }; \
QMetaObject::metacall(object, QMetaObject::WriteProperty, property->coreIndex(), argv);
const int propType = property->propType().id();
const QMetaType propType = property->propType();
// functions are already handled, except for the QJSValue case
Q_ASSERT(!value.as<FunctionObject>() || propType == qMetaTypeId<QJSValue>());
Q_ASSERT(!value.as<FunctionObject>() || propType == QMetaType::fromType<QJSValue>());
if (value.isNull() && property->isQObject()) {
PROPERTY_STORE(QObject*, nullptr);
} else if (value.isUndefined() && property->isResettable()) {
void *a[] = { nullptr };
QMetaObject::metacall(object, QMetaObject::ResetProperty, property->coreIndex(), a);
} else if (value.isUndefined() && propType == qMetaTypeId<QVariant>()) {
} else if (value.isUndefined() && propType == QMetaType::fromType<QVariant>()) {
PROPERTY_STORE(QVariant, QVariant());
} else if (value.isUndefined() && propType == QMetaType::QJsonValue) {
} else if (value.isUndefined() && propType == QMetaType::fromType<QJsonValue>()) {
PROPERTY_STORE(QJsonValue, QJsonValue(QJsonValue::Undefined));
} else if (propType == qMetaTypeId<QJSValue>()) {
} else if (propType == QMetaType::fromType<QJSValue>()) {
PROPERTY_STORE(QJSValue, QJSValuePrivate::fromReturnedValue(value.asReturnedValue()));
} else if (value.isUndefined() && propType != qMetaTypeId<QQmlScriptString>()) {
} else if (value.isUndefined() && propType != QMetaType::fromType<QQmlScriptString>()) {
QString error = QLatin1String("Cannot assign [undefined] to ");
if (!property->propType().name())
if (!propType.name())
error += QLatin1String("[unknown property type]");
else
error += QLatin1String(property->propType().name());
error += QLatin1String(propType.name());
scope.engine->throwError(error);
return;
} else if (property->propType().id() == QMetaType::Int && value.isNumber()) {
} else if (propType == QMetaType::fromType<int>() && value.isNumber()) {
PROPERTY_STORE(int, value.asDouble());
} else if (propType == QMetaType::QReal && value.isNumber()) {
} else if (propType == QMetaType::fromType<qreal>() && value.isNumber()) {
PROPERTY_STORE(qreal, qreal(value.asDouble()));
} else if (propType == QMetaType::Float && value.isNumber()) {
} else if (propType == QMetaType::fromType<float>() && value.isNumber()) {
PROPERTY_STORE(float, float(value.asDouble()));
} else if (propType == QMetaType::Double && value.isNumber()) {
} else if (propType == QMetaType::fromType<double>() && value.isNumber()) {
PROPERTY_STORE(double, double(value.asDouble()));
} else if (propType == QMetaType::QString && value.isString()) {
} else if (propType == QMetaType::fromType<QString>() && value.isString()) {
PROPERTY_STORE(QString, value.toQStringNoThrow());
} else if (property->isVarProperty()) {
QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
Q_ASSERT(vmemo);
vmemo->setVMEProperty(property->coreIndex(), value);
} else if (propType == qMetaTypeId<QQmlScriptString>() && (value.isUndefined() || value.isPrimitive())) {
} else if (propType == QMetaType::fromType<QQmlScriptString>()
&& (value.isUndefined() || value.isPrimitive())) {
QQmlScriptString ss(value.toQStringNoThrow(), nullptr /* context */, object);
if (value.isNumber()) {
ss.d->numberValue = value.toNumber();
@ -638,7 +640,7 @@ void QObjectWrapper::setProperty(
if (property->isQList())
v = scope.engine->toVariant(value, QMetaType::fromType<QList<QObject *> >());
else
v = scope.engine->toVariant(value, property->propType());
v = scope.engine->toVariant(value, propType);
QQmlRefPointer<QQmlContextData> callingQmlContext = scope.engine->callingQmlContext();
if (!QQmlPropertyPrivate::write(object, *property, v, callingQmlContext)) {
@ -646,7 +648,7 @@ void QObjectWrapper::setProperty(
? "an unknown type"
: QMetaType(v.userType()).name();
const char *targetTypeName = QMetaType(property->propType()).name();
const char *targetTypeName = propType.name();
if (!targetTypeName)
targetTypeName = "an unregistered type";
@ -1321,8 +1323,11 @@ public:
};
struct CallArgument {
inline CallArgument();
inline ~CallArgument();
Q_DISABLE_COPY_MOVE(CallArgument);
CallArgument() = default;
~CallArgument() { cleanup(); }
inline void *dataPtr();
inline void initAsType(QMetaType type);
@ -1330,12 +1335,14 @@ struct CallArgument {
inline ReturnedValue toValue(ExecutionEngine *);
private:
CallArgument(const CallArgument &);
// QVariantWrappedType denotes that we're storing a QVariant, but we mean
// the type inside the QVariant, not QVariant itself.
enum { QVariantWrappedType = -1 };
inline void cleanup();
template <class T, class M>
void fromContainerValue(const QV4::Object *object, int type, M CallArgument::*member, bool &queryEngine);
bool fromContainerValue(const QV4::Value &object, M CallArgument::*member);
union {
float floatValue;
@ -1343,6 +1350,7 @@ private:
quint32 intValue;
bool boolValue;
QObject *qobjectPtr;
#if QT_CONFIG(qml_sequence_object)
std::vector<int> *stdVectorIntPtr;
std::vector<qreal> *stdVectorRealPtr;
std::vector<bool> *stdVectorBoolPtr;
@ -1350,6 +1358,7 @@ private:
std::vector<QUrl> *stdVectorQUrlPtr;
#if QT_CONFIG(qml_itemmodel)
std::vector<QModelIndex> *stdVectorQModelIndexPtr;
#endif
#endif
char allocData[MaxSizeOf7<QVariant,
@ -1374,7 +1383,7 @@ private:
QJsonValue *jsonValuePtr;
};
int type;
int type = QMetaType::UnknownType;
};
}
@ -1789,168 +1798,232 @@ static const QQmlPropertyData *ResolveOverloaded(
}
}
CallArgument::CallArgument()
: type(QMetaType::UnknownType)
{
}
CallArgument::~CallArgument()
{
cleanup();
}
void CallArgument::cleanup()
{
if (type == QMetaType::QString) {
switch (type) {
case QMetaType::QString:
qstringPtr->~QString();
} else if (type == QMetaType::QByteArray) {
break;
case QMetaType::QByteArray:
qbyteArrayPtr->~QByteArray();
} else if (type == -1 || type == QMetaType::QVariant) {
break;
case QMetaType::QVariant:
case QVariantWrappedType:
qvariantPtr->~QVariant();
} else if (type == qMetaTypeId<QJSValue>()) {
qjsValuePtr->~QJSValue();
} else if (type == qMetaTypeId<QList<QObject *> >()) {
qlistPtr->~QList<QObject *>();
} else if (type == QMetaType::QJsonArray) {
break;
case QMetaType::QJsonArray:
jsonArrayPtr->~QJsonArray();
} else if (type == QMetaType::QJsonObject) {
break;
case QMetaType::QJsonObject:
jsonObjectPtr->~QJsonObject();
} else if (type == QMetaType::QJsonValue) {
break;
case QMetaType::QJsonValue:
jsonValuePtr->~QJsonValue();
break;
default:
if (type == qMetaTypeId<QJSValue>()) {
qjsValuePtr->~QJSValue();
break;
}
if (type == qMetaTypeId<QList<QObject *> >()) {
qlistPtr->~QList<QObject *>();
break;
}
// The sequence types need no cleanup because we don't own them.
break;
}
}
void *CallArgument::dataPtr()
{
if (type == -1)
switch (type) {
case QMetaType::UnknownType:
return nullptr;
case QVariantWrappedType:
return qvariantPtr->data();
else if (type == qMetaTypeId<std::vector<int>>())
default:
#if QT_CONFIG(qml_sequence_object)
if (type == qMetaTypeId<std::vector<int>>())
return stdVectorIntPtr;
else if (type == qMetaTypeId<std::vector<qreal>>())
if (type == qMetaTypeId<std::vector<qreal>>())
return stdVectorRealPtr;
else if (type == qMetaTypeId<std::vector<bool>>())
if (type == qMetaTypeId<std::vector<bool>>())
return stdVectorBoolPtr;
else if (type == qMetaTypeId<std::vector<QString>>())
if (type == qMetaTypeId<std::vector<QString>>())
return stdVectorQStringPtr;
else if (type == qMetaTypeId<std::vector<QUrl>>())
if (type == qMetaTypeId<std::vector<QUrl>>())
return stdVectorQUrlPtr;
#if QT_CONFIG(qml_itemmodel)
else if (type == qMetaTypeId<std::vector<QModelIndex>>())
if (type == qMetaTypeId<std::vector<QModelIndex>>())
return stdVectorQModelIndexPtr;
#endif
else if (type != 0)
#endif
break;
}
return (void *)&allocData;
return nullptr;
}
void CallArgument::initAsType(QMetaType metaType)
{
if (type != 0) { cleanup(); type = 0; }
const int callType = metaType.id();
if (callType == QMetaType::UnknownType || callType == QMetaType::Void) return;
if (type != QMetaType::UnknownType)
cleanup();
if (callType == qMetaTypeId<QJSValue>()) {
qjsValuePtr = new (&allocData) QJSValue();
type = callType;
} else if (callType == QMetaType::Int ||
callType == QMetaType::UInt ||
callType == QMetaType::Bool ||
callType == QMetaType::Double ||
callType == QMetaType::Float) {
type = callType;
} else if (callType == QMetaType::QObjectStar) {
type = metaType.id();
switch (type) {
case QMetaType::Void:
type = QMetaType::UnknownType;
break;
case QMetaType::UnknownType:
case QMetaType::Int:
case QMetaType::UInt:
case QMetaType::Bool:
case QMetaType::Double:
case QMetaType::Float:
break;
case QMetaType::QObjectStar:
qobjectPtr = nullptr;
type = callType;
} else if (callType == QMetaType::QString) {
break;
case QMetaType::QString:
qstringPtr = new (&allocData) QString();
type = callType;
} else if (callType == QMetaType::QVariant) {
type = callType;
break;
case QMetaType::QVariant:
qvariantPtr = new (&allocData) QVariant();
} else if (callType == qMetaTypeId<QList<QObject *> >()) {
type = callType;
qlistPtr = new (&allocData) QList<QObject *>();
} else if (callType == QMetaType::QJsonArray) {
type = callType;
break;
case QMetaType::QJsonArray:
jsonArrayPtr = new (&allocData) QJsonArray();
} else if (callType == QMetaType::QJsonObject) {
type = callType;
break;
case QMetaType::QJsonObject:
jsonObjectPtr = new (&allocData) QJsonObject();
} else if (callType == QMetaType::QJsonValue) {
type = callType;
break;
case QMetaType::QJsonValue:
jsonValuePtr = new (&allocData) QJsonValue();
} else {
type = -1;
break;
default: {
if (metaType == QMetaType::fromType<QJSValue>()) {
qjsValuePtr = new (&allocData) QJSValue();
break;
}
if (metaType == QMetaType::fromType<QList<QObject *>>()) {
qlistPtr = new (&allocData) QList<QObject *>();
break;
}
type = QVariantWrappedType;
qvariantPtr = new (&allocData) QVariant(metaType, (void *)nullptr);
break;
}
}
}
#if QT_CONFIG(qml_sequence_object)
template <class T, class M>
void CallArgument::fromContainerValue(const QV4::Object *object, int callType, M CallArgument::*member, bool &queryEngine)
bool CallArgument::fromContainerValue(const QV4::Value &value, M CallArgument::*member)
{
const QV4::Object *object = value.as<QV4::Object>();
if (object && object->isListType()) {
T* ptr = static_cast<T*>(QV4::SequencePrototype::getRawContainerPtr(object, callType));
if (ptr) {
if (T* ptr = static_cast<T *>(QV4::SequencePrototype::getRawContainerPtr(object, type))) {
(this->*member) = ptr;
type = callType;
queryEngine = false;
return true;
}
}
(this->*member) = nullptr;
return false;
}
#endif
bool CallArgument::fromValue(QMetaType metaType, QV4::ExecutionEngine *engine, const QV4::Value &value)
bool CallArgument::fromValue(
QMetaType metaType, QV4::ExecutionEngine *engine, const QV4::Value &value)
{
if (type != 0) {
if (type != QMetaType::UnknownType)
cleanup();
type = 0;
}
QV4::Scope scope(engine);
type = metaType.id();
const int callType = metaType.id();
bool queryEngine = false;
if (callType == qMetaTypeId<QJSValue>()) {
qjsValuePtr = new (&allocData) QJSValue;
QJSValuePrivate::setValue(qjsValuePtr, value.asReturnedValue());
type = qMetaTypeId<QJSValue>();
} else if (callType == QMetaType::Int) {
switch (type) {
case QMetaType::Int:
intValue = quint32(value.toInt32());
type = callType;
} else if (callType == QMetaType::UInt) {
return true;
case QMetaType::UInt:
intValue = quint32(value.toUInt32());
type = callType;
} else if (callType == QMetaType::Bool) {
return true;
case QMetaType::Bool:
boolValue = value.toBoolean();
type = callType;
} else if (callType == QMetaType::Double) {
return true;
case QMetaType::Double:
doubleValue = double(value.toNumber());
type = callType;
} else if (callType == QMetaType::Float) {
return true;
case QMetaType::Float:
floatValue = float(value.toNumber());
type = callType;
} else if (callType == QMetaType::QString) {
if (value.isNull() || value.isUndefined())
return true;
case QMetaType::QString:
if (value.isNullOrUndefined())
qstringPtr = new (&allocData) QString();
else
qstringPtr = new (&allocData) QString(value.toQStringNoThrow());
type = callType;
} else if (callType == QMetaType::QObjectStar) {
qobjectPtr = nullptr;
type = callType;
if (const QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>())
return true;
case QMetaType::QObjectStar:
if (const QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>()) {
qobjectPtr = qobjectWrapper->object();
else if (const QV4::QQmlTypeWrapper *qmlTypeWrapper = value.as<QV4::QQmlTypeWrapper>())
queryEngine = qmlTypeWrapper->isSingleton();
else if (!value.isNull() && !value.isUndefined()) // null and undefined are nullptr
return false;
} else if (callType == qMetaTypeId<QVariant>()) {
qvariantPtr = new (&allocData) QVariant(scope.engine->toVariant(value, QMetaType {}));
type = callType;
} else if (callType == qMetaTypeId<QList<QObject*> >()) {
return true;
}
if (const QV4::QQmlTypeWrapper *qmlTypeWrapper = value.as<QV4::QQmlTypeWrapper>()) {
if (qmlTypeWrapper->isSingleton()) {
// Convert via QVariant below.
// TODO: Can't we just do qobjectPtr = qmlTypeWrapper->object() instead?
break;
}
// If this is a plain type wrapper without an instance,
// then indeed it's an undefined parameter.
// (although we might interpret that as const QMetaObject *).
// TODO: But what if it's an attached object?
type = QMetaType::UnknownType;
return true;
}
qobjectPtr = nullptr;
return value.isNullOrUndefined(); // null and undefined are nullptr
case QMetaType::QVariant:
qvariantPtr = new (&allocData) QVariant(engine->toVariant(value, QMetaType {}));
return true;
case QMetaType::QJsonArray: {
QV4::Scope scope(engine);
QV4::ScopedArrayObject a(scope, value);
jsonArrayPtr = new (&allocData) QJsonArray(QV4::JsonObject::toJsonArray(a));
return true;
}
case QMetaType::QJsonObject: {
QV4::Scope scope(engine);
QV4::ScopedObject o(scope, value);
jsonObjectPtr = new (&allocData) QJsonObject(QV4::JsonObject::toJsonObject(o));
return true;
}
case QMetaType::QJsonValue:
jsonValuePtr = new (&allocData) QJsonValue(QV4::JsonObject::toJsonValue(value));
return true;
case QMetaType::Void:
type = QMetaType::UnknownType;
// TODO: This only doesn't leak because a default constructed QVariant doesn't allocate.
*qvariantPtr = QVariant();
return true;
default:
if (type == qMetaTypeId<QJSValue>()) {
qjsValuePtr = new (&allocData) QJSValue;
QJSValuePrivate::setValue(qjsValuePtr, value.asReturnedValue());
return true;
}
if (type == qMetaTypeId<QList<QObject*> >()) {
qlistPtr = new (&allocData) QList<QObject *>();
type = callType;
QV4::Scope scope(engine);
QV4::ScopedArrayObject array(scope, value);
if (array) {
Scoped<QV4::QObjectWrapper> qobjectWrapper(scope);
@ -1963,89 +2036,76 @@ bool CallArgument::fromValue(QMetaType metaType, QV4::ExecutionEngine *engine, c
o = qobjectWrapper->object();
qlistPtr->append(o);
}
} else {
return true;
}
if (const QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>()) {
qlistPtr->append(qobjectWrapper->object());
} else {
return true;
}
qlistPtr->append(nullptr);
if (!value.isNull() && !value.isUndefined())
return false;
return value.isNullOrUndefined();
}
}
} else if (callType == QMetaType::QJsonArray) {
QV4::ScopedArrayObject a(scope, value);
jsonArrayPtr = new (&allocData) QJsonArray(QV4::JsonObject::toJsonArray(a));
type = callType;
} else if (callType == QMetaType::QJsonObject) {
QV4::ScopedObject o(scope, value);
jsonObjectPtr = new (&allocData) QJsonObject(QV4::JsonObject::toJsonObject(o));
type = callType;
} else if (callType == QMetaType::QJsonValue) {
jsonValuePtr = new (&allocData) QJsonValue(QV4::JsonObject::toJsonValue(value));
type = callType;
} else if (callType == QMetaType::Void) {
*qvariantPtr = QVariant();
#if QT_CONFIG(qml_sequence_object)
} else if (callType == qMetaTypeId<std::vector<int>>()
|| callType == qMetaTypeId<std::vector<qreal>>()
|| callType == qMetaTypeId<std::vector<bool>>()
|| callType == qMetaTypeId<std::vector<QString>>()
|| callType == qMetaTypeId<std::vector<QUrl>>()
#if QT_CONFIG(qml_itemmodel)
|| callType == qMetaTypeId<std::vector<QModelIndex>>()
#endif
) {
queryEngine = true;
const QV4::Object* object = value.as<QV4::Object>();
if (callType == qMetaTypeId<std::vector<int>>()) {
stdVectorIntPtr = nullptr;
fromContainerValue<std::vector<int>>(object, callType, &CallArgument::stdVectorIntPtr, queryEngine);
} else if (callType == qMetaTypeId<std::vector<qreal>>()) {
stdVectorRealPtr = nullptr;
fromContainerValue<std::vector<qreal>>(object, callType, &CallArgument::stdVectorRealPtr, queryEngine);
} else if (callType == qMetaTypeId<std::vector<bool>>()) {
stdVectorBoolPtr = nullptr;
fromContainerValue<std::vector<bool>>(object, callType, &CallArgument::stdVectorBoolPtr, queryEngine);
} else if (callType == qMetaTypeId<std::vector<QString>>()) {
stdVectorQStringPtr = nullptr;
fromContainerValue<std::vector<QString>>(object, callType, &CallArgument::stdVectorQStringPtr, queryEngine);
} else if (callType == qMetaTypeId<std::vector<QUrl>>()) {
stdVectorQUrlPtr = nullptr;
fromContainerValue<std::vector<QUrl>>(object, callType, &CallArgument::stdVectorQUrlPtr, queryEngine);
#if QT_CONFIG(qml_itemmodel)
} else if (callType == qMetaTypeId<std::vector<QModelIndex>>()) {
stdVectorQModelIndexPtr = nullptr;
fromContainerValue<std::vector<QModelIndex>>(object, callType, &CallArgument::stdVectorQModelIndexPtr, queryEngine);
#endif
}
#endif
} else if (metaType.flags()
& (QMetaType::PointerToQObject | QMetaType::PointerToGadget)) {
if (metaType.flags() & (QMetaType::PointerToQObject | QMetaType::PointerToGadget)) {
// You can assign null or undefined to any pointer. The result is a nullptr.
if (value.isNull() || value.isUndefined()) {
if (value.isNullOrUndefined()) {
qvariantPtr = new (&allocData) QVariant(metaType, nullptr);
type = callType;
} else {
queryEngine = true;
return true;
}
} else {
queryEngine = true;
break;
}
if (queryEngine) {
#if QT_CONFIG(qml_sequence_object)
if (type == qMetaTypeId<std::vector<int>>()) {
if (fromContainerValue<std::vector<int>>(value, &CallArgument::stdVectorIntPtr))
return true;
} else if (type == qMetaTypeId<std::vector<qreal>>()) {
if (fromContainerValue<std::vector<qreal>>(value, &CallArgument::stdVectorRealPtr))
return true;
} else if (type == qMetaTypeId<std::vector<bool>>()) {
if (fromContainerValue<std::vector<bool>>(value, &CallArgument::stdVectorBoolPtr))
return true;
} else if (type == qMetaTypeId<std::vector<QString>>()) {
if (fromContainerValue<std::vector<QString>>(value, &CallArgument::stdVectorQStringPtr))
return true;
} else if (type == qMetaTypeId<std::vector<QUrl>>()) {
if (fromContainerValue<std::vector<QUrl>>(value, &CallArgument::stdVectorQUrlPtr))
return true;
#if QT_CONFIG(qml_itemmodel)
} else if (type == qMetaTypeId<std::vector<QModelIndex>>()) {
if (fromContainerValue<std::vector<QModelIndex>>(
value, &CallArgument::stdVectorQModelIndexPtr)) {
return true;
}
#endif
}
#endif
break;
}
// Convert via QVariant through the QML engine.
qvariantPtr = new (&allocData) QVariant();
type = -1;
type = QVariantWrappedType;
QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : nullptr;
QVariant v = scope.engine->toVariant(value, metaType);
const QQmlEnginePrivate *ep = engine->qmlEngine()
? QQmlEnginePrivate::get(engine->qmlEngine())
: nullptr;
QVariant v = engine->toVariant(value, metaType);
if (v.metaType() == metaType) {
*qvariantPtr = v;
} else if (v.canConvert(metaType)) {
*qvariantPtr = v;
*qvariantPtr = std::move(v);
return true;
}
if (v.canConvert(metaType)) {
*qvariantPtr = std::move(v);
qvariantPtr->convert(metaType);
} else {
QQmlMetaObject mo = ep ? ep->rawMetaObjectForType(metaType) : QQmlMetaObject();
return true;
}
const QQmlMetaObject mo = ep ? ep->rawMetaObjectForType(metaType) : QQmlMetaObject();
if (!mo.isNull()) {
QObject *obj = QQmlMetaType::toQObject(v);
@ -2061,66 +2121,71 @@ bool CallArgument::fromValue(QMetaType metaType, QV4::ExecutionEngine *engine, c
*qvariantPtr = QVariant(metaType, (void *)nullptr);
return false;
}
}
return true;
}
QV4::ReturnedValue CallArgument::toValue(QV4::ExecutionEngine *engine)
{
QV4::Scope scope(engine);
if (type == qMetaTypeId<QJSValue>()) {
// The QJSValue can be passed around via dataPtr()
QJSValuePrivate::manageStringOnV4Heap(engine, qjsValuePtr);
return QJSValuePrivate::asReturnedValue(qjsValuePtr);
} else if (type == QMetaType::Int) {
switch (type) {
case QMetaType::Int:
return QV4::Encode(int(intValue));
} else if (type == QMetaType::UInt) {
case QMetaType::UInt:
return QV4::Encode((uint)intValue);
} else if (type == QMetaType::Bool) {
case QMetaType::Bool:
return QV4::Encode(boolValue);
} else if (type == QMetaType::Double) {
case QMetaType::Double:
return QV4::Encode(doubleValue);
} else if (type == QMetaType::Float) {
case QMetaType::Float:
return QV4::Encode(floatValue);
} else if (type == QMetaType::QString) {
case QMetaType::QString:
return QV4::Encode(engine->newString(*qstringPtr));
} else if (type == QMetaType::QByteArray) {
case QMetaType::QByteArray:
return QV4::Encode(engine->newArrayBuffer(*qbyteArrayPtr));
} else if (type == QMetaType::QObjectStar) {
QObject *object = qobjectPtr;
if (object)
QQmlData::get(object, true)->setImplicitDestructible();
return QV4::QObjectWrapper::wrap(scope.engine, object);
} else if (type == qMetaTypeId<QList<QObject *> >()) {
// XXX Can this be made more by using Array as a prototype and implementing
// directly against QList<QObject*>?
QList<QObject *> &list = *qlistPtr;
QV4::ScopedArrayObject array(scope, scope.engine->newArrayObject());
array->arrayReserve(list.count());
QV4::ScopedValue v(scope);
for (int ii = 0; ii < list.count(); ++ii)
array->arrayPut(ii, (v = QV4::QObjectWrapper::wrap(scope.engine, list.at(ii))));
array->setArrayLengthUnchecked(list.count());
return array.asReturnedValue();
} else if (type == QMetaType::QJsonArray) {
return QV4::JsonObject::fromJsonArray(scope.engine, *jsonArrayPtr);
} else if (type == QMetaType::QJsonObject) {
return QV4::JsonObject::fromJsonObject(scope.engine, *jsonObjectPtr);
} else if (type == QMetaType::QJsonValue) {
return QV4::JsonObject::fromJsonValue(scope.engine, *jsonValuePtr);
} else if (type == -1 || type == qMetaTypeId<QVariant>()) {
QVariant value = *qvariantPtr;
QV4::ScopedValue rv(scope, scope.engine->fromVariant(value));
case QMetaType::QObjectStar:
if (qobjectPtr)
QQmlData::get(qobjectPtr, true)->setImplicitDestructible();
return QV4::QObjectWrapper::wrap(engine, qobjectPtr);
case QMetaType::QJsonArray:
return QV4::JsonObject::fromJsonArray(engine, *jsonArrayPtr);
case QMetaType::QJsonObject:
return QV4::JsonObject::fromJsonObject(engine, *jsonObjectPtr);
case QMetaType::QJsonValue:
return QV4::JsonObject::fromJsonValue(engine, *jsonValuePtr);
case QMetaType::QVariant:
case QVariantWrappedType: {
QV4::Scope scope(engine);
QV4::ScopedValue rv(scope, scope.engine->fromVariant(*qvariantPtr));
QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, rv);
if (!!qobjectWrapper) {
if (QObject *object = qobjectWrapper->object())
QQmlData::get(object, true)->setImplicitDestructible();
}
return rv->asReturnedValue();
} else {
return QV4::Encode::undefined();
}
default:
break;
}
if (type == qMetaTypeId<QJSValue>()) {
// The QJSValue can be passed around via dataPtr()
QJSValuePrivate::manageStringOnV4Heap(engine, qjsValuePtr);
return QJSValuePrivate::asReturnedValue(qjsValuePtr);
}
if (type == qMetaTypeId<QList<QObject *> >()) {
// XXX Can this be made more by using Array as a prototype and implementing
// directly against QList<QObject*>?
QList<QObject *> &list = *qlistPtr;
QV4::Scope scope(engine);
QV4::ScopedArrayObject array(scope, engine->newArrayObject());
array->arrayReserve(list.count());
QV4::ScopedValue v(scope);
for (int ii = 0; ii < list.count(); ++ii)
array->arrayPut(ii, (v = QV4::QObjectWrapper::wrap(engine, list.at(ii))));
array->setArrayLengthUnchecked(list.count());
return array.asReturnedValue();
}
return QV4::Encode::undefined();
}
ReturnedValue QObjectMethod::create(ExecutionContext *scope, QObject *object, int index)