diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2023-06-22 12:03:28 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2023-06-23 21:23:05 +0200 |
commit | 29f3bbb0622f2449741b45e002a059850993561c (patch) | |
tree | 9ca92bf486cbf9609e46ea0792ddac6021118d4f /src/qml/qml/qqmlglobal.cpp | |
parent | 8889089d0fd8ab93f623a98992588087e45399a5 (diff) |
QtQml: Improve qmlobject_can_qml_cast
Composite types don't readily expose their metaobjects because they are
expensive to create. We can use the property caches instead.
Change-Id: Idd5cc96d22489b9d0868d3955bf373c479e17c69
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qml/qml/qqmlglobal.cpp')
-rw-r--r-- | src/qml/qml/qqmlglobal.cpp | 45 |
1 files changed, 39 insertions, 6 deletions
diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp index 730687fc2f..045b6fc948 100644 --- a/src/qml/qml/qqmlglobal.cpp +++ b/src/qml/qml/qqmlglobal.cpp @@ -924,12 +924,45 @@ bool qmlobject_can_cpp_cast(QObject *object, const QMetaObject *mo) return object->metaObject()->inherits(mo); } -bool qmlobject_can_qml_cast(QObject *object, const QMetaObject *mo) -{ - Q_ASSERT(mo); - if (const QQmlData *ddata = ddata_for_cast(object)) - return ddata->propertyCache->metaObject()->inherits(mo); - return object->metaObject()->inherits(mo); +bool qmlobject_can_qml_cast(QObject *object, const QQmlType &type) +{ + Q_ASSERT(type.isValid()); + + // A non-composite type will always have a metaobject. + const QMetaObject *typeMetaObject = type.metaObject(); + const QQmlPropertyCache::ConstPtr typePropertyCache = typeMetaObject + ? QQmlPropertyCache::ConstPtr() + : QQmlMetaType::findPropertyCacheInCompositeTypes(type.typeId()); + + if (const QQmlData *ddata = ddata_for_cast(object)) { + for (const QQmlPropertyCache *propertyCache = ddata->propertyCache.data(); propertyCache; + propertyCache = propertyCache->parent().data()) { + + if (typeMetaObject) { + // Prefer the metaobject inheritance mechanism, since it is more accurate. + // + // Assume the object can be casted to the type. Then, if we have a type metaobject, + // the object's property cache inheritance has to contain it. Otherwise we would + // end up with diverging metaobject hierarchies if we created the object's + // metaobject. This would be a disaster. + if (const QMetaObject *objectMetaObject = propertyCache->metaObject()) + return objectMetaObject->inherits(typeMetaObject); + } else { + // This is a best effort attempt. There are a number of ways for the + // property caches to be unrelated but the types still convertible. + // Multiple property caches can hold the same metaobject, for example for + // versions of non-composite types. + if (propertyCache == typePropertyCache.data()) + return true; + } + } + } + + // If nothing else works, we have to create the metaobjects. + + return object->metaObject()->inherits(typeMetaObject + ? typeMetaObject + : (typePropertyCache ? typePropertyCache->createMetaObject() : nullptr)); } QT_END_NAMESPACE |