aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4engine.cpp
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2023-06-07 09:40:00 +0200
committerUlf Hermann <ulf.hermann@qt.io>2023-06-08 05:17:58 +0200
commitcd16a5ffb9d798b08dba0cdfbef045b4b2dd0f08 (patch)
tree702f7ef9e7a037939d267acc6fee48cda8427bfd /src/qml/jsruntime/qv4engine.cpp
parenta4de7389bf90ab62c5d12391f9bb0d03da9b4b82 (diff)
QML: Allow coercing variant objects to their own type
This allows passing unregistered value types through QML. Pick-to: 6.5 6.6 Task-number: QTBUG-114340 Change-Id: I6fa5adadf2d406d2d5f3a83fb922e9d547e7ead9 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qml/jsruntime/qv4engine.cpp')
-rw-r--r--src/qml/jsruntime/qv4engine.cpp82
1 files changed, 49 insertions, 33 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 93887f74c6..9a56ad9d88 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -2672,42 +2672,58 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
return true;
const bool isPointer = (metaType.flags() & QMetaType::IsPointer);
- if (value.as<QV4::VariantObject>() && isPointer) {
- const QByteArray pointedToTypeName = QByteArray(metaType.name()).chopped(1);
- const QMetaType valueType = QMetaType::fromName(pointedToTypeName);
- QVariant &var = value.as<QV4::VariantObject>()->d()->data();
- if (valueType == var.metaType()) {
- // We have T t, T* is requested, so return &t.
- *reinterpret_cast<void* *>(data) = var.data();
+ const QV4::VariantObject *variantObject = value.as<QV4::VariantObject>();
+ if (variantObject) {
+ // Actually a reference, because we're poking it for its data() below and we want
+ // the _original_ data, not some copy.
+ const QVariant &var = variantObject->d()->data();
+
+ if (var.metaType() == metaType) {
+ metaType.destruct(data);
+ metaType.construct(data, var.data());
return true;
- } else if (Object *o = value.objectValue()) {
- // Look in the prototype chain.
- QV4::Scope scope(o->engine());
- QV4::ScopedObject proto(scope, o->getPrototypeOf());
- while (proto) {
- bool canCast = false;
- if (QV4::VariantObject *vo = proto->as<QV4::VariantObject>()) {
- const QVariant &v = vo->d()->data();
- canCast = (metaType == v.metaType());
- }
- else if (proto->as<QV4::QObjectWrapper>()) {
- QV4::ScopedObject p(scope, proto.getPointer());
- if (QObject *qobject = qtObjectFromJS(p)) {
- if (const QMetaObject *metaObject = metaType.metaObject())
- canCast = metaObject->cast(qobject) != nullptr;
- else
- canCast = qobject->qt_metacast(pointedToTypeName);
+ }
+
+ if (isPointer) {
+ const QByteArray pointedToTypeName = QByteArray(metaType.name()).chopped(1);
+ const QMetaType valueType = QMetaType::fromName(pointedToTypeName);
+
+ if (valueType == var.metaType()) {
+ // ### Qt7: Remove this. Returning pointers to potentially gc'd data is crazy.
+ // We have T t, T* is requested, so return &t.
+ *reinterpret_cast<const void **>(data) = var.data();
+ return true;
+ } else if (Object *o = value.objectValue()) {
+ // Look in the prototype chain.
+ QV4::Scope scope(o->engine());
+ QV4::ScopedObject proto(scope, o->getPrototypeOf());
+ while (proto) {
+ bool canCast = false;
+ if (QV4::VariantObject *vo = proto->as<QV4::VariantObject>()) {
+ const QVariant &v = vo->d()->data();
+ canCast = (metaType == v.metaType());
}
+ else if (proto->as<QV4::QObjectWrapper>()) {
+ QV4::ScopedObject p(scope, proto.getPointer());
+ if (QObject *qobject = qtObjectFromJS(p)) {
+ if (const QMetaObject *metaObject = metaType.metaObject())
+ canCast = metaObject->cast(qobject) != nullptr;
+ else
+ canCast = qobject->qt_metacast(pointedToTypeName);
+ }
+ }
+ if (canCast) {
+ const QMetaType varType = var.metaType();
+ if (varType.flags() & QMetaType::IsPointer) {
+ *reinterpret_cast<const void **>(data)
+ = *reinterpret_cast<void *const *>(var.data());
+ } else {
+ *reinterpret_cast<const void **>(data) = var.data();
+ }
+ return true;
+ }
+ proto = proto->getPrototypeOf();
}
- if (canCast) {
- const QMetaType varType = var.metaType();
- if (varType.flags() & QMetaType::IsPointer)
- *reinterpret_cast<void* *>(data) = *reinterpret_cast<void* *>(var.data());
- else
- *reinterpret_cast<void* *>(data) = var.data();
- return true;
- }
- proto = proto->getPrototypeOf();
}
}
} else if (value.isNull() && isPointer) {