diff options
Diffstat (limited to 'src/qml/qml/qqmlmetatypedata.cpp')
-rw-r--r-- | src/qml/qml/qqmlmetatypedata.cpp | 219 |
1 files changed, 124 insertions, 95 deletions
diff --git a/src/qml/qml/qqmlmetatypedata.cpp b/src/qml/qml/qqmlmetatypedata.cpp index c2150225c3..bc7e762e53 100644 --- a/src/qml/qml/qqmlmetatypedata.cpp +++ b/src/qml/qml/qqmlmetatypedata.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2019 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// 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" @@ -51,21 +15,24 @@ QQmlMetaTypeData::QQmlMetaTypeData() QQmlMetaTypeData::~QQmlMetaTypeData() { - for (TypeModules::const_iterator i = uriToModule.constBegin(), cend = uriToModule.constEnd(); i != cend; ++i) - delete *i; - for (QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator it = propertyCaches.begin(), end = propertyCaches.end(); - it != end; ++it) - (*it)->release(); + { + // 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.count(); ++i) { + for (int i = 0; i < types.size(); ++i) { if (!types.at(i).isValid()) { types[i] = QQmlType(priv); priv->index = i; @@ -74,71 +41,119 @@ void QQmlMetaTypeData::registerType(QQmlTypePrivate *priv) } } types.append(QQmlType(priv)); - priv->index = types.count() - 1; + priv->index = types.size() - 1; priv->release(); } -void QQmlMetaTypeData::registerModuleTypes(const QQmlMetaTypeData::VersionedUri &versionedUri) +QQmlMetaTypeData::VersionedUri::VersionedUri(const std::unique_ptr<QQmlTypeModule> &module) + : uri(module->module()), majorVersion(module->majorVersion()) { - auto function = moduleTypeRegistrationFunctions.constFind(versionedUri); - if (function != moduleTypeRegistrationFunctions.constEnd()) - (*function)(); } -QQmlPropertyCache *QQmlMetaTypeData::propertyCacheForMinorVersion(int index, int minorVersion) const +QQmlTypeModule *QQmlMetaTypeData::findTypeModule(const QString &module, QTypeRevision version) { - return (index < typePropertyCaches.length()) - ? typePropertyCaches.at(index).value(minorVersion).data() + 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; } -void QQmlMetaTypeData::setPropertyCacheForMinorVersion(int index, int minorVersion, - QQmlPropertyCache *cache) +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.length()) + if (index >= typePropertyCaches.size()) typePropertyCaches.resize(index + 1); - typePropertyCaches[index][minorVersion] = cache; + typePropertyCaches[index][version] = cache; } -void QQmlMetaTypeData::clearPropertyCachesForMinorVersion(int index) +void QQmlMetaTypeData::clearPropertyCachesForVersion(int index) { - if (index < typePropertyCaches.length()) + if (index < typePropertyCaches.size()) typePropertyCaches[index].clear(); } -QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QMetaObject *metaObject, int minorVersion) +QQmlPropertyCache::ConstPtr QQmlMetaTypeData::propertyCache( + const QMetaObject *metaObject, QTypeRevision version) { - if (QQmlPropertyCache *rv = propertyCaches.value(metaObject)) + if (QQmlPropertyCache::ConstPtr rv = propertyCaches.value(metaObject)) return rv; - if (!metaObject->superClass()) { - QQmlPropertyCache *rv = new QQmlPropertyCache(metaObject); + 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 *super = propertyCache(metaObject->superClass(), minorVersion); - QQmlPropertyCache *rv = super->copyAndAppend(metaObject, minorVersion); - propertyCaches.insert(metaObject, rv); + return rv; } -QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int minorVersion) +QQmlPropertyCache::ConstPtr QQmlMetaTypeData::propertyCache( + const QQmlType &type, QTypeRevision version) { Q_ASSERT(type.isValid()); - if (QQmlPropertyCache *pc = propertyCacheForMinorVersion(type.index(), minorVersion)) + if (auto pc = propertyCacheForVersion(type.index(), version)) return pc; QVector<QQmlType> types; - int maxMinorVersion = 0; + 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(), type.majorVersion(), minorVersion); + QQmlType t = QQmlMetaType::qmlType(metaObject, type.module(), combinedVersion); if (t.isValid()) { - maxMinorVersion = qMax(maxMinorVersion, t.minorVersion()); + maxMinorVersion = qMax(maxMinorVersion, t.version().minorVersion()); types << t; } else { types << QQmlType(); @@ -147,32 +162,30 @@ QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int min metaObject = metaObject->superClass(); } - if (QQmlPropertyCache *pc = propertyCacheForMinorVersion(type.index(), maxMinorVersion)) { - setPropertyCacheForMinorVersion(type.index(), minorVersion, pc); + const QTypeRevision maxVersion = QTypeRevision::fromVersion(combinedVersion.majorVersion(), + maxMinorVersion); + if (auto pc = propertyCacheForVersion(type.index(), maxVersion)) { + setPropertyCacheForVersion(type.index(), maxVersion, pc); return pc; } - QQmlPropertyCache *raw = propertyCache(type.metaObject(), minorVersion); - - bool hasCopied = false; + QQmlPropertyCache::ConstPtr raw = propertyCache(type.metaObject(), combinedVersion); + QQmlPropertyCache::Ptr copied; - for (int ii = 0; ii < types.count(); ++ii) { + for (int ii = 0; ii < types.size(); ++ii) { const QQmlType ¤tType = types.at(ii); if (!currentType.isValid()) continue; - int rev = currentType.metaObjectRevision(); - int moIndex = types.count() - 1 - ii; + QTypeRevision rev = currentType.metaObjectRevision(); + int moIndex = types.size() - 1 - ii; if (raw->allowedRevision(moIndex) != rev) { - if (!hasCopied) { - // TODO: The copy should be mutable, and the original should be const - // Considering this, the setAllowedRevision() below does not violate - // the immutability of already published property caches. - raw = raw->copy(); - hasCopied = true; + if (copied.isNull()) { + copied = raw->copy(); + raw = copied; } - raw->setAllowedRevision(moIndex, rev); + copied->setAllowedRevision(moIndex, rev); } } @@ -198,12 +211,12 @@ QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int min !overloadError && iter != raw->stringCache.end(); ++iter) { - QQmlPropertyData *d = *iter; + const QQmlPropertyData *d = *iter; if (raw->isAllowedInRevision(d)) continue; // Not excluded - no problems // check that a regular "name" overload isn't happening - QQmlPropertyData *current = d; + const QQmlPropertyData *current = d; while (!overloadError && current) { current = d->overrideData(current); if (current && raw->isAllowedInRevision(current)) @@ -219,15 +232,31 @@ QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int min } #endif - setPropertyCacheForMinorVersion(type.index(), minorVersion, raw); - - if (hasCopied) - raw->release(); + setPropertyCacheForVersion(type.index(), version, raw); - if (minorVersion != maxMinorVersion) - setPropertyCacheForMinorVersion(type.index(), maxMinorVersion, 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 |