qmlobject_cast: Make it useful again

The Qt 6 implementation of qmlobject_cast simply accessed the metaObject
of the object (canConvert -> QQmlMetaObject::QQmlMetaObject(QObject*)
-> QOject:metaObject). That would directly cause the creation of
dynamic meta-objects, if they weren't created so far.

Given that we still didn't get rid of the property-cache in QML, use it
to optimize this code path:
If the object has some associated QQmlData, retrieve it and check if we
have a  property cache. If we do, retrieve the first C++ meta object
from it. We can safely ignore any dynamic meta-objects as T must be a
static meta-object. Then do the normal inheritance check with the first
C++ meta-object and T::staticMetaObject.
If we don't have a property cache, fall back to the previous
implementation (but without the QQmlMetaObject detour).

Change-Id: Ie23d1a3dac6bf343ee2bc31e04c4592681ad9995
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
This commit is contained in:
Fabian Kosmale 2023-03-16 15:30:57 +01:00 committed by Shawn Rutledge
parent 51c6db3f3d
commit 677cd24de6
2 changed files with 15 additions and 1 deletions

View File

@ -596,6 +596,16 @@ void QQmlApplication::setDomain(const QString &arg)
QCoreApplication::instance()->setOrganizationDomain(arg); QCoreApplication::instance()->setOrganizationDomain(arg);
} }
bool qmlobject_can_cast(QObject *object, const QMetaObject *mo)
{
Q_ASSERT(object);
Q_ASSERT(mo);
auto ddata = QQmlData::get(object, false);
if (!ddata || ! ddata->propertyCache)
return object->metaObject()->inherits(mo);
return ddata->propertyCache->firstCppMetaObject()->inherits(mo);
}
QT_END_NAMESPACE QT_END_NAMESPACE
#include "moc_qqmlglobal_p.cpp" #include "moc_qqmlglobal_p.cpp"

View File

@ -122,6 +122,8 @@ do { \
QMetaObject::disconnect(sender, signalIdx, receiver, methodIdx); \ QMetaObject::disconnect(sender, signalIdx, receiver, methodIdx); \
} while (0) } while (0)
Q_QML_PRIVATE_EXPORT bool qmlobject_can_cast(QObject *object, const QMetaObject *mo);
/*! /*!
This method is identical to qobject_cast<T>() except that it does not require lazy This method is identical to qobject_cast<T>() except that it does not require lazy
QMetaObjects to be built, so should be preferred in all QML code that might interact QMetaObjects to be built, so should be preferred in all QML code that might interact
@ -137,7 +139,9 @@ do { \
template<class T> template<class T>
T qmlobject_cast(QObject *object) T qmlobject_cast(QObject *object)
{ {
if (object && QQmlMetaObject::canConvert(object, &reinterpret_cast<T>(object)->staticMetaObject)) if (!object)
return nullptr;
if (qmlobject_can_cast(object, &(std::remove_pointer_t<T>::staticMetaObject)))
return static_cast<T>(object); return static_cast<T>(object);
else else
return nullptr; return nullptr;