aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlmetatypedata.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml/qqmlmetatypedata.cpp')
-rw-r--r--src/qml/qml/qqmlmetatypedata.cpp262
1 files changed, 262 insertions, 0 deletions
diff --git a/src/qml/qml/qqmlmetatypedata.cpp b/src/qml/qml/qqmlmetatypedata.cpp
new file mode 100644
index 0000000000..bc7e762e53
--- /dev/null
+++ b/src/qml/qml/qqmlmetatypedata.cpp
@@ -0,0 +1,262 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qqmlmetatypedata_p.h"
+
+#include <private/qqmltype_p_p.h>
+#include <private/qqmltypemodule_p.h>
+#include <private/qqmlpropertycache_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlMetaTypeData::QQmlMetaTypeData()
+{
+}
+
+QQmlMetaTypeData::~QQmlMetaTypeData()
+{
+ {
+ // Unregister all remaining composite types.
+ // Avoid deletion recursion (via QQmlTypePrivate dtor) by moving them out of the way first.
+ CompositeTypes emptyComposites;
+ emptyComposites.swap(compositeTypes);
+ }
+
+ propertyCaches.clear();
+ // Do this before the attached properties disappear.
+ types.clear();
+ undeletableTypes.clear();
+ qDeleteAll(metaTypeToValueType);
+}
+
+// This expects a "fresh" QQmlTypePrivate and adopts its reference.
+void QQmlMetaTypeData::registerType(QQmlTypePrivate *priv)
+{
+ for (int i = 0; i < types.size(); ++i) {
+ if (!types.at(i).isValid()) {
+ types[i] = QQmlType(priv);
+ priv->index = i;
+ priv->release();
+ return;
+ }
+ }
+ types.append(QQmlType(priv));
+ priv->index = types.size() - 1;
+ priv->release();
+}
+
+QQmlMetaTypeData::VersionedUri::VersionedUri(const std::unique_ptr<QQmlTypeModule> &module)
+ : uri(module->module()), majorVersion(module->majorVersion())
+{
+}
+
+QQmlTypeModule *QQmlMetaTypeData::findTypeModule(const QString &module, QTypeRevision version)
+{
+ const auto qqtm = std::lower_bound(
+ uriToModule.begin(), uriToModule.end(), VersionedUri(module, version),
+ std::less<QQmlMetaTypeData::VersionedUri>());
+ if (qqtm == uriToModule.end())
+ return nullptr;
+
+ QQmlTypeModule *candidate = qqtm->get();
+ return (candidate->module() == module && candidate->majorVersion() == version.majorVersion())
+ ? candidate
+ : nullptr;
+}
+
+QQmlTypeModule *QQmlMetaTypeData::addTypeModule(std::unique_ptr<QQmlTypeModule> module)
+{
+ QQmlTypeModule *ret = module.get();
+ uriToModule.emplace_back(std::move(module));
+ std::sort(uriToModule.begin(), uriToModule.end(),
+ [](const std::unique_ptr<QQmlTypeModule> &a,
+ const std::unique_ptr<QQmlTypeModule> &b) {
+ const int diff = a->module().compare(b->module());
+ return diff < 0 || (diff == 0 && a->majorVersion() < b->majorVersion());
+ });
+ return ret;
+}
+
+bool QQmlMetaTypeData::registerModuleTypes(const QString &uri)
+{
+ auto function = moduleTypeRegistrationFunctions.constFind(uri);
+ if (function != moduleTypeRegistrationFunctions.constEnd()) {
+ (*function)();
+ return true;
+ }
+ return false;
+}
+
+QQmlPropertyCache::ConstPtr QQmlMetaTypeData::propertyCacheForVersion(
+ int index, QTypeRevision version) const
+{
+ return (index < typePropertyCaches.size())
+ ? typePropertyCaches.at(index).value(version)
+ : QQmlPropertyCache::ConstPtr();
+}
+
+void QQmlMetaTypeData::setPropertyCacheForVersion(int index, QTypeRevision version,
+ const QQmlPropertyCache::ConstPtr &cache)
+{
+ if (index >= typePropertyCaches.size())
+ typePropertyCaches.resize(index + 1);
+ typePropertyCaches[index][version] = cache;
+}
+
+void QQmlMetaTypeData::clearPropertyCachesForVersion(int index)
+{
+ if (index < typePropertyCaches.size())
+ typePropertyCaches[index].clear();
+}
+
+QQmlPropertyCache::ConstPtr QQmlMetaTypeData::propertyCache(
+ const QMetaObject *metaObject, QTypeRevision version)
+{
+ if (QQmlPropertyCache::ConstPtr rv = propertyCaches.value(metaObject))
+ return rv;
+
+ QQmlPropertyCache::ConstPtr rv;
+ if (const QMetaObject *superMeta = metaObject->superClass())
+ rv = propertyCache(superMeta, version)->copyAndAppend(metaObject, version);
+ else
+ rv = QQmlPropertyCache::createStandalone(metaObject);
+
+ const auto *mop = reinterpret_cast<const QMetaObjectPrivate *>(metaObject->d.data);
+ if (!(mop->flags & DynamicMetaObject))
+ propertyCaches.insert(metaObject, rv);
+
+ return rv;
+}
+
+QQmlPropertyCache::ConstPtr QQmlMetaTypeData::propertyCache(
+ const QQmlType &type, QTypeRevision version)
+{
+ Q_ASSERT(type.isValid());
+
+ if (auto pc = propertyCacheForVersion(type.index(), version))
+ return pc;
+
+ QVector<QQmlType> types;
+
+ quint8 maxMinorVersion = 0;
+
+ const QMetaObject *metaObject = type.metaObject();
+ Q_ASSERT(metaObject);
+
+ const QTypeRevision combinedVersion = version.hasMajorVersion()
+ ? version
+ : (version.hasMinorVersion()
+ ? QTypeRevision::fromVersion(type.version().majorVersion(),
+ version.minorVersion())
+ : QTypeRevision::fromMajorVersion(type.version().majorVersion()));
+
+ while (metaObject) {
+ QQmlType t = QQmlMetaType::qmlType(metaObject, type.module(), combinedVersion);
+ if (t.isValid()) {
+ maxMinorVersion = qMax(maxMinorVersion, t.version().minorVersion());
+ types << t;
+ } else {
+ types << QQmlType();
+ }
+
+ metaObject = metaObject->superClass();
+ }
+
+ const QTypeRevision maxVersion = QTypeRevision::fromVersion(combinedVersion.majorVersion(),
+ maxMinorVersion);
+ if (auto pc = propertyCacheForVersion(type.index(), maxVersion)) {
+ setPropertyCacheForVersion(type.index(), maxVersion, pc);
+ return pc;
+ }
+
+ QQmlPropertyCache::ConstPtr raw = propertyCache(type.metaObject(), combinedVersion);
+ QQmlPropertyCache::Ptr copied;
+
+ for (int ii = 0; ii < types.size(); ++ii) {
+ const QQmlType &currentType = types.at(ii);
+ if (!currentType.isValid())
+ continue;
+
+ QTypeRevision rev = currentType.metaObjectRevision();
+ int moIndex = types.size() - 1 - ii;
+
+ if (raw->allowedRevision(moIndex) != rev) {
+ if (copied.isNull()) {
+ copied = raw->copy();
+ raw = copied;
+ }
+ copied->setAllowedRevision(moIndex, rev);
+ }
+ }
+
+ // Test revision compatibility - the basic rule is:
+ // * Anything that is excluded, cannot overload something that is not excluded *
+
+ // Signals override:
+ // * other signals and methods of the same name.
+ // * properties named on<Signal Name>
+ // * automatic <property name>Changed notify signals
+
+ // Methods override:
+ // * other methods of the same name
+
+ // Properties override:
+ // * other elements of the same name
+
+#if 0
+ bool overloadError = false;
+ QString overloadName;
+
+ for (QQmlPropertyCache::StringCache::ConstIterator iter = raw->stringCache.begin();
+ !overloadError && iter != raw->stringCache.end();
+ ++iter) {
+
+ const QQmlPropertyData *d = *iter;
+ if (raw->isAllowedInRevision(d))
+ continue; // Not excluded - no problems
+
+ // check that a regular "name" overload isn't happening
+ const QQmlPropertyData *current = d;
+ while (!overloadError && current) {
+ current = d->overrideData(current);
+ if (current && raw->isAllowedInRevision(current))
+ overloadError = true;
+ }
+ }
+
+ if (overloadError) {
+ if (hasCopied) raw->release();
+
+ error.setDescription(QLatin1String("Type ") + type.qmlTypeName() + QLatin1Char(' ') + QString::number(type.majorVersion()) + QLatin1Char('.') + QString::number(minorVersion) + QLatin1String(" contains an illegal property \"") + overloadName + QLatin1String("\". This is an error in the type's implementation."));
+ return 0;
+ }
+#endif
+
+ setPropertyCacheForVersion(type.index(), version, raw);
+
+ if (version != maxVersion)
+ setPropertyCacheForVersion(type.index(), maxVersion, raw);
+
+ return raw;
+}
+
+static QQmlPropertyCache::ConstPtr propertyCacheForPotentialInlineComponentType(
+ QMetaType t, const QQmlMetaTypeData::CompositeTypes::const_iterator &iter) {
+ if (t != (*iter)->metaType()) {
+ // this is an inline component, and what we have in the iterator is currently the parent compilation unit
+ for (auto &&icDatum: (*iter)->inlineComponentData)
+ if (icDatum.qmlType.typeId() == t)
+ return (*iter)->propertyCaches.at(icDatum.objectIndex);
+ }
+ return (*iter)->rootPropertyCache();
+}
+
+QQmlPropertyCache::ConstPtr QQmlMetaTypeData::findPropertyCacheInCompositeTypes(QMetaType t) const
+{
+ auto iter = compositeTypes.constFind(t.iface());
+ return (iter == compositeTypes.constEnd())
+ ? QQmlPropertyCache::ConstPtr()
+ : propertyCacheForPotentialInlineComponentType(t, iter);
+}
+
+QT_END_NAMESPACE