diff options
author | Lars Knoll <lars.knoll@qt.io> | 2017-08-22 17:17:57 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2017-08-22 17:17:57 +0200 |
commit | f1aff1f2d495562460a87d351e62c06109045a3a (patch) | |
tree | 93e4659421a3dc1fc664b539bf7e48ce28f64e84 /src/qml/qml | |
parent | 842ada7b04d68cd37df2556bf50b48d8a5f39ec4 (diff) | |
parent | 46ed14da325c6c0382c0bc54cacc347d2d7f2b0a (diff) |
Merge remote-tracking branch 'origin/dev' into wip/new-backend
Change-Id: Iff06429f948ac6cdec77a9e5bb8c5375c56fe705
Diffstat (limited to 'src/qml/qml')
35 files changed, 1472 insertions, 994 deletions
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index 911df78595..fa60ba3216 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -54,6 +54,7 @@ #include <QVariant> #include <QtCore/qdebug.h> +#include <QVector> QT_BEGIN_NAMESPACE @@ -195,7 +196,7 @@ class QQmlNonbindingBinding: public QQmlBinding { protected: void doUpdate(const DeleteWatcher &watcher, - QQmlPropertyData::WriteFlags flags, QV4::Scope &scope) Q_DECL_OVERRIDE Q_DECL_FINAL + QQmlPropertyData::WriteFlags flags, QV4::Scope &scope) Q_DECL_OVERRIDE { auto ep = QQmlEnginePrivate::get(scope.engine); ep->referenceScarceResources(); @@ -295,6 +296,50 @@ protected: } }; +class QQmlTranslationBinding : public GenericBinding<QMetaType::QString> { +public: + QQmlTranslationBinding(QV4::CompiledData::CompilationUnit *compilationUnit, const QV4::CompiledData::Binding *binding) + { + setCompilationUnit(compilationUnit); + m_binding = binding; + setSourceLocation(QQmlSourceLocation(compilationUnit->fileName(), binding->valueLocation.line, binding->valueLocation.column)); + } + + void doUpdate(const DeleteWatcher &watcher, + QQmlPropertyData::WriteFlags flags, QV4::Scope &) Q_DECL_OVERRIDE Q_DECL_FINAL + { + if (watcher.wasDeleted()) + return; + + if (!isAddedToObject() || hasError()) + return; + + const QString result = m_binding->valueAsString(m_compilationUnit->data); + + Q_ASSERT(targetObject()); + + QQmlPropertyData *pd; + QQmlPropertyData vpd; + getPropertyData(&pd, &vpd); + Q_ASSERT(pd); + doStore(result, pd, flags); + } + +private: + const QV4::CompiledData::Binding *m_binding; +}; + +QQmlBinding *QQmlBinding::createTranslationBinding(QV4::CompiledData::CompilationUnit *unit, const QV4::CompiledData::Binding *binding, QObject *obj, QQmlContextData *ctxt) +{ + QQmlTranslationBinding *b = new QQmlTranslationBinding(unit, binding); + + b->setNotifyOnValueChanged(true); + b->QQmlJavaScriptExpression::setContext(ctxt); + b->setScopeObject(obj); + + return b; +} + Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData, const QV4::Value &result, @@ -513,7 +558,12 @@ void QQmlBinding::getPropertyData(QQmlPropertyData **propertyData, QQmlPropertyD Q_ASSERT(propertyData); QQmlData *data = QQmlData::get(*m_target, false); - Q_ASSERT(data && data->propertyCache); + Q_ASSERT(data); + + if (Q_UNLIKELY(!data->propertyCache)) { + data->propertyCache = QQmlEnginePrivate::get(context()->engine)->cache(m_target->metaObject()); + data->propertyCache->addref(); + } *propertyData = data->propertyCache->property(m_targetIndex.coreIndex()); Q_ASSERT(*propertyData); @@ -528,6 +578,37 @@ void QQmlBinding::getPropertyData(QQmlPropertyData **propertyData, QQmlPropertyD } } +QVector<QQmlProperty> QQmlBinding::dependencies() const +{ + QVector<QQmlProperty> dependencies; + if (!m_target.data()) + return dependencies; + + for (const auto &guardList : { permanentGuards, activeGuards }) { + for (QQmlJavaScriptExpressionGuard *guard = guardList.first(); guard; guard = guardList.next(guard)) { + if (guard->signalIndex() == -1) // guard's sender is a QQmlNotifier, not a QObject*. + continue; + + QObject *senderObject = guard->senderAsObject(); + if (!senderObject) + continue; + + const QMetaObject *senderMeta = senderObject->metaObject(); + if (!senderMeta) + continue; + + for (int i = 0; i < senderMeta->propertyCount(); i++) { + QMetaProperty property = senderMeta->property(i); + if (property.notifySignalIndex() == QMetaObjectPrivate::signal(senderMeta, guard->signalIndex()).methodIndex()) { + dependencies.push_back(QQmlProperty(senderObject, QString::fromUtf8(senderObject->metaObject()->property(i).name()))); + } + } + } + } + + return dependencies; +} + class QObjectPointerBinding: public QQmlNonbindingBinding { QQmlMetaObject targetMetaObject; diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h index 0f2fb329f5..38d59a8919 100644 --- a/src/qml/qml/qqmlbinding_p.h +++ b/src/qml/qml/qqmlbinding_p.h @@ -77,6 +77,8 @@ public: const QString &url = QString(), quint16 lineNumber = 0); static QQmlBinding *create(const QQmlPropertyData *property, QV4::Function *function, QObject *obj, QQmlContextData *ctxt, QV4::ExecutionContext *scope); + static QQmlBinding *createTranslationBinding(QV4::CompiledData::CompilationUnit *unit, const QV4::CompiledData::Binding *binding, + QObject *obj, QQmlContextData *ctxt); ~QQmlBinding(); void setTarget(const QQmlProperty &); @@ -100,6 +102,15 @@ public: QString expressionIdentifier() const override; void expressionChanged() override; + /** + * This method returns a snapshot of the currently tracked dependencies of + * this binding. The dependencies can change upon reevaluation. This method is + * used in GammaRay to visualize binding hierarchies. + * + * Call this method from the UI thread. + */ + QVector<QQmlProperty> dependencies() const; + protected: virtual void doUpdate(const DeleteWatcher &watcher, QQmlPropertyData::WriteFlags flags, QV4::Scope &scope) = 0; diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp index 6ad641b8b1..cc6e75a39c 100644 --- a/src/qml/qml/qqmlcustomparser.cpp +++ b/src/qml/qml/qqmlcustomparser.cpp @@ -135,7 +135,7 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const if (scope != QLatin1String("Qt")) { if (imports.isNull()) return -1; - QQmlType *type = 0; + QQmlType type; if (imports.isT1()) { imports.asT1()->resolveType(scope, &type, 0, 0, 0); @@ -145,7 +145,7 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const type = result.type; } - if (!type) + if (!type.isValid()) return -1; int dot2 = script.indexOf('.', dot+1); @@ -153,9 +153,9 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const QByteArray enumValue = script.mid(dot2Valid ? dot2 + 1 : dot + 1); QByteArray scopedEnumName = (dot2Valid ? script.mid(dot + 1, dot2 - dot - 1) : QByteArray()); if (!scopedEnumName.isEmpty()) - return type->scopedEnumValue(engine, scopedEnumName, enumValue, ok); + return type.scopedEnumValue(engine, scopedEnumName, enumValue, ok); else - return type->enumValue(engine, QHashedCStringRef(enumValue.constData(), enumValue.length()), ok); + return type.enumValue(engine, QHashedCStringRef(enumValue.constData(), enumValue.length()), ok); } QByteArray enumValue = script.mid(dot + 1); @@ -177,12 +177,10 @@ const QMetaObject *QQmlCustomParser::resolveType(const QString& name) const { if (!imports.isT1()) return nullptr; - QQmlType *qmltype = 0; + QQmlType qmltype; if (!imports.asT1()->resolveType(name, &qmltype, 0, 0, 0)) return nullptr; - if (!qmltype) - return nullptr; - return qmltype->metaObject(); + return qmltype.metaObject(); } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index fd516c9815..194c58b805 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -596,7 +596,7 @@ The following functions are also on the Qt object. \li application.font \endlist - \sa Screen, Window, {QtQuick::Window::screen}{Window.screen} + \sa Screen, Window, {QtQuick.Window::Window::screen}{Window.screen} */ /*! @@ -683,8 +683,6 @@ QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e) QQmlEnginePrivate::~QQmlEnginePrivate() { - typedef QHash<QPair<QQmlType *, int>, QQmlPropertyCache *>::const_iterator TypePropertyCacheIt; - if (inProgressCreations) qWarning() << QQmlEngine::tr("There are still \"%1\" items in the process of being created at engine destruction.").arg(inProgressCreations); @@ -702,8 +700,8 @@ QQmlEnginePrivate::~QQmlEnginePrivate() if (incubationController) incubationController->d = 0; incubationController = 0; - for (TypePropertyCacheIt iter = typePropertyCache.cbegin(), end = typePropertyCache.cend(); iter != end; ++iter) - (*iter)->release(); + QQmlMetaType::freeUnusedTypesAndCaches(); + for (auto iter = m_compositeTypes.cbegin(), end = m_compositeTypes.cend(); iter != end; ++iter) { iter.value()->isRegisteredWithEngine = false; @@ -1028,9 +1026,9 @@ QQmlEngine::~QQmlEngine() // we do this here and not in the private dtor since otherwise a crash can // occur (if we are the QObject parent of the QObject singleton instance) // XXX TODO: performance -- store list of singleton types separately? - const QList<QQmlType*> singletonTypes = QQmlMetaType::qmlSingletonTypes(); - for (QQmlType *currType : singletonTypes) - currType->singletonInstanceInfo()->destroy(this); + QList<QQmlType> singletonTypes = QQmlMetaType::qmlSingletonTypes(); + for (const QQmlType &currType : singletonTypes) + currType.singletonInstanceInfo()->destroy(this); delete d->rootContext; d->rootContext = 0; @@ -1328,6 +1326,30 @@ void QQmlEngine::setOutputWarningsToStandardError(bool enabled) } /*! + Refreshes all binding expressions that use strings marked for translation. + + Call this function after you have installed a new translator with + QCoreApplication::installTranslator, to ensure that your user-interface + shows up-to-date translations. + + \note Due to a limitation in the implementation, this function + refreshes all the engine's bindings, not only those that use strings + marked for translation. + This may be optimized in a future release. + + \since 5.10 +*/ +void QQmlEngine::retranslate() +{ + Q_D(QQmlEngine); + QQmlContextData *context = QQmlContextData::get(d->rootContext)->childContexts; + while (context) { + context->refreshExpressions(); + context = context->nextChild; + } +} + +/*! Returns the QQmlContext for the \a object, or 0 if no context has been set. @@ -1447,6 +1469,9 @@ bool QQmlEngine::event(QEvent *e) Q_D(QQmlEngine); if (e->type() == QEvent::User) d->doDeleteInEngineThread(); + else if (e->type() == QEvent::LanguageChange) { + retranslate(); + } return QJSEngine::event(e); } @@ -2200,108 +2225,6 @@ QString QQmlEnginePrivate::offlineStorageDatabaseDirectory() const return q->offlineStoragePath() + QDir::separator() + QLatin1String("Databases") + QDir::separator(); } -QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersion) -{ - QList<QQmlType *> types; - - int maxMinorVersion = 0; - - const QMetaObject *metaObject = type->metaObject(); - - while (metaObject) { - QQmlType *t = QQmlMetaType::qmlType(metaObject, type->module(), - type->majorVersion(), minorVersion); - if (t) { - maxMinorVersion = qMax(maxMinorVersion, t->minorVersion()); - types << t; - } else { - types << 0; - } - - metaObject = metaObject->superClass(); - } - - if (QQmlPropertyCache *c = typePropertyCache.value(qMakePair(type, maxMinorVersion))) { - c->addref(); - typePropertyCache.insert(qMakePair(type, minorVersion), c); - return c; - } - - QQmlPropertyCache *raw = cache(type->metaObject()); - - bool hasCopied = false; - - for (int ii = 0; ii < types.count(); ++ii) { - QQmlType *currentType = types.at(ii); - if (!currentType) - continue; - - int rev = currentType->metaObjectRevision(); - int moIndex = types.count() - 1 - ii; - - if (raw->allowedRevisionCache[moIndex] != rev) { - if (!hasCopied) { - raw = raw->copy(); - hasCopied = true; - } - raw->allowedRevisionCache[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) { - - QQmlPropertyData *d = *iter; - if (raw->isAllowedInRevision(d)) - continue; // Not excluded - no problems - - // check that a regular "name" overload isn't happening - 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 - - if (!hasCopied) raw->addref(); - typePropertyCache.insert(qMakePair(type, minorVersion), raw); - - if (minorVersion != maxMinorVersion) { - raw->addref(); - typePropertyCache.insert(qMakePair(type, maxMinorVersion), raw); - } - - return raw; -} - bool QQmlEnginePrivate::isQObject(int t) { Locker locker(this); @@ -2325,26 +2248,17 @@ QQmlMetaType::TypeCategory QQmlEnginePrivate::typeCategory(int t) const Locker locker(this); if (m_compositeTypes.contains(t)) return QQmlMetaType::Object; - else if (m_qmlLists.contains(t)) - return QQmlMetaType::List; - else - return QQmlMetaType::typeCategory(t); + return QQmlMetaType::typeCategory(t); } bool QQmlEnginePrivate::isList(int t) const { - Locker locker(this); - return m_qmlLists.contains(t) || QQmlMetaType::isList(t); + return QQmlMetaType::isList(t); } int QQmlEnginePrivate::listType(int t) const { - Locker locker(this); - QHash<int, int>::ConstIterator iter = m_qmlLists.constFind(t); - if (iter != m_qmlLists.cend()) - return *iter; - else - return QQmlMetaType::listType(t); + return QQmlMetaType::listType(t); } QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const @@ -2354,8 +2268,8 @@ QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const if (iter != m_compositeTypes.cend()) { return QQmlMetaObject((*iter)->rootPropertyCache()); } else { - QQmlType *type = QQmlMetaType::qmlType(t); - return QQmlMetaObject(type?type->baseMetaObject():0); + QQmlType type = QQmlMetaType::qmlType(t); + return QQmlMetaObject(type.baseMetaObject()); } } @@ -2366,8 +2280,8 @@ QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const if (iter != m_compositeTypes.cend()) { return QQmlMetaObject((*iter)->rootPropertyCache()); } else { - QQmlType *type = QQmlMetaType::qmlType(t); - return QQmlMetaObject(type?type->metaObject():0); + QQmlType type = QQmlMetaType::qmlType(t); + return QQmlMetaObject(type.metaObject()); } } @@ -2378,9 +2292,9 @@ QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t) if (iter != m_compositeTypes.cend()) { return (*iter)->rootPropertyCache(); } else { - QQmlType *type = QQmlMetaType::qmlType(t); + QQmlType type = QQmlMetaType::qmlType(t); locker.unlock(); - return type?cache(type->metaObject()):0; + return type.isValid() ? cache(type.metaObject()) : 0; } } @@ -2391,54 +2305,28 @@ QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t) if (iter != m_compositeTypes.cend()) { return (*iter)->rootPropertyCache(); } else { - QQmlType *type = QQmlMetaType::qmlType(t); + QQmlType type = QQmlMetaType::qmlType(t); locker.unlock(); - return type?cache(type->baseMetaObject()):0; + return type.isValid() ? cache(type.baseMetaObject()) : 0; } } void QQmlEnginePrivate::registerInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit) { - QByteArray name = compilationUnit->rootPropertyCache()->className(); - - QByteArray ptr = name + '*'; - QByteArray lst = "QQmlListProperty<" + name + '>'; - - int ptr_type = QMetaType::registerNormalizedType(ptr, - QtMetaTypePrivate::QMetaTypeFunctionHelper<QObject*>::Destruct, - QtMetaTypePrivate::QMetaTypeFunctionHelper<QObject*>::Construct, - sizeof(QObject*), - static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QObject*>::Flags), - 0); - int lst_type = QMetaType::registerNormalizedType(lst, - QtMetaTypePrivate::QMetaTypeFunctionHelper<QQmlListProperty<QObject> >::Destruct, - QtMetaTypePrivate::QMetaTypeFunctionHelper<QQmlListProperty<QObject> >::Construct, - sizeof(QQmlListProperty<QObject>), - static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QQmlListProperty<QObject> >::Flags), - static_cast<QMetaObject*>(0)); - - compilationUnit->metaTypeId = ptr_type; - compilationUnit->listMetaTypeId = lst_type; compilationUnit->isRegisteredWithEngine = true; Locker locker(this); - m_qmlLists.insert(lst_type, ptr_type); // The QQmlCompiledData is not referenced here, but it is removed from this // hash in the QQmlCompiledData destructor - m_compositeTypes.insert(ptr_type, compilationUnit); + m_compositeTypes.insert(compilationUnit->metaTypeId, compilationUnit); } void QQmlEnginePrivate::unregisterInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit) { - int ptr_type = compilationUnit->metaTypeId; - int lst_type = compilationUnit->listMetaTypeId; + compilationUnit->isRegisteredWithEngine = false; Locker locker(this); - m_qmlLists.remove(lst_type); - m_compositeTypes.remove(ptr_type); - - QMetaType::unregisterType(ptr_type); - QMetaType::unregisterType(lst_type); + m_compositeTypes.remove(compilationUnit->metaTypeId); } bool QQmlEnginePrivate::isTypeLoaded(const QUrl &url) const diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h index 8cada954fe..2bf4c0497b 100644 --- a/src/qml/qml/qqmlengine.h +++ b/src/qml/qml/qqmlengine.h @@ -144,6 +144,10 @@ public: bool outputWarningsToStandardError() const; void setOutputWarningsToStandardError(bool); +public Q_SLOTS: + void retranslate(); + +public: static QQmlContext *contextForObject(const QObject *); static void setContextForObject(QObject *, QQmlContext *); diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 1bdeacd524..da8ea24ea0 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -208,7 +208,7 @@ public: QString offlineStorageDatabaseDirectory() const; // These methods may be called from the loader thread - inline QQmlPropertyCache *cache(QQmlType *, int); + inline QQmlPropertyCache *cache(const QQmlType &, int); using QJSEnginePrivate::cache; // These methods may be called from the loader thread @@ -259,13 +259,8 @@ public: mutable QMutex networkAccessManagerMutex; private: - // Must be called locked - QQmlPropertyCache *createCache(QQmlType *, int); - // These members must be protected by a QQmlEnginePrivate::Locker as they are required by // the threaded loader. Only access them through their respective accessor methods. - QHash<QPair<QQmlType *, int>, QQmlPropertyCache *> typePropertyCache; - QHash<int, int> m_qmlLists; QHash<int, QV4::CompiledData::CompilationUnit *> m_compositeTypes; static bool s_designerMode; @@ -375,17 +370,15 @@ Returns a QQmlPropertyCache for \a type with \a minorVersion. The returned cache is not referenced, so if it is to be stored, call addref(). */ -QQmlPropertyCache *QQmlEnginePrivate::cache(QQmlType *type, int minorVersion) +QQmlPropertyCache *QQmlEnginePrivate::cache(const QQmlType &type, int minorVersion) { - Q_ASSERT(type); + Q_ASSERT(type.isValid()); - if (minorVersion == -1 || !type->containsRevisionedAttributes()) - return cache(type->metaObject()); + if (minorVersion == -1 || !type.containsRevisionedAttributes()) + return cache(type.metaObject()); Locker locker(this); - QQmlPropertyCache *rv = typePropertyCache.value(qMakePair(type, minorVersion)); - if (!rv) rv = createCache(type, minorVersion); - return rv; + return QQmlMetaType::propertyCache(type, minorVersion); } QV8Engine *QQmlEnginePrivate::getV8Engine(QQmlEngine *e) diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp index c4b705230a..35dbaccbbe 100644 --- a/src/qml/qml/qqmlexpression.cpp +++ b/src/qml/qml/qqmlexpression.cpp @@ -202,7 +202,6 @@ QQmlExpression::QQmlExpression(QQmlContextData *ctxt, QObject *scope, */ QQmlExpression::~QQmlExpression() { - clearError(); } /*! diff --git a/src/qml/qml/qqmlextensioninterface.h b/src/qml/qml/qqmlextensioninterface.h index ef56d5e312..62b9b26569 100644 --- a/src/qml/qml/qqmlextensioninterface.h +++ b/src/qml/qml/qqmlextensioninterface.h @@ -66,7 +66,10 @@ public: Q_DECLARE_INTERFACE(QQmlTypesExtensionInterface, "org.qt-project.Qt.QQmlTypesExtensionInterface/1.0") +// NOTE: When changing this to a new version and deciding to add backup code to +// continue to support the previous version, make sure to support both of these iids. #define QQmlExtensionInterface_iid "org.qt-project.Qt.QQmlExtensionInterface/1.0" +#define QQmlExtensionInterface_iid_old "org.qt-project.Qt.QQmlExtensionInterface" Q_DECLARE_INTERFACE(QQmlExtensionInterface, QQmlExtensionInterface_iid) diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index ee5b38717b..7c9dcb1826 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -142,13 +142,13 @@ bool isPathAbsolute(const QString &path) Errors (if there are any) are placed into \a errors, if it is nonzero. Note that errors are treated as fatal if \a errors is not set. */ -QQmlType *fetchOrCreateTypeForUrl(const QString &urlString, const QHashedStringRef& typeName, +QQmlType fetchOrCreateTypeForUrl(const QString &urlString, const QHashedStringRef& typeName, bool isCompositeSingleton, QList<QQmlError> *errors, int majorVersion=-1, int minorVersion=-1) { QUrl url(urlString); // ### unfortunate (costly) conversion - QQmlType *ret = QQmlMetaType::qmlType(url); - if (ret) + QQmlType ret = QQmlMetaType::qmlType(url); + if (ret.isValid()) return ret; int dot = typeName.indexOf(QLatin1Char('.')); @@ -183,7 +183,7 @@ QQmlType *fetchOrCreateTypeForUrl(const QString &urlString, const QHashedStringR minorVersion, buf.constData() }; - ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeSingletonRegistration, ®)); + ret = QQmlMetaType::registerCompositeSingletonType(reg); } else { QQmlPrivate::RegisterCompositeType reg = { url, @@ -192,13 +192,13 @@ QQmlType *fetchOrCreateTypeForUrl(const QString &urlString, const QHashedStringR minorVersion, buf.constData() }; - ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeRegistration, ®)); + ret = QQmlMetaType::registerCompositeType(reg); } // This means that the type couldn't be found by URL, but could not be // registered either, meaning we most likely were passed some kind of bad // data. - if (!ret) { + if (!ret.isValid()) { if (!errors) // Cannot list errors properly, just quit qFatal("%s", QQmlMetaType::typeRegistrationFailures().join('\n').toLatin1().constData()); QQmlError error; @@ -295,7 +295,8 @@ public: QList<QQmlError> *errors); bool resolveType(const QHashedStringRef &type, int *vmajor, int *vminor, - QQmlType** type_return, QList<QQmlError> *errors); + QQmlType* type_return, QList<QQmlError> *errors, + QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion); QUrl baseUrl; QString base; @@ -420,13 +421,14 @@ void QQmlImports::populateCache(QQmlTypeNameCache *cache) const const QQmlImportNamespace &set = *ns; // positioning is important; we must create the namespace even if there is no module. - QQmlTypeNameCache::Import &typeimport = cache->m_namedImports[set.prefix]; + QQmlImportRef &typeimport = cache->m_namedImports[set.prefix]; typeimport.m_qualifier = set.prefix; for (int ii = set.imports.count() - 1; ii >= 0; --ii) { const QQmlImportInstance *import = set.imports.at(ii); QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->majversion); if (module) { + QQmlImportRef &typeimport = cache->m_namedImports[set.prefix]; typeimport.modules.append(QQmlTypeModuleVersion(module, import->minversion)); } } @@ -619,8 +621,9 @@ QString QQmlImports::versionString(int vmaj, int vmin, ImportVersion version) \sa addFileImport(), addLibraryImport */ bool QQmlImports::resolveType(const QHashedStringRef &type, - QQmlType** type_return, int *vmaj, int *vmin, - QQmlImportNamespace** ns_return, QList<QQmlError> *errors) const + QQmlType* type_return, int *vmaj, int *vmin, + QQmlImportNamespace** ns_return, QList<QQmlError> *errors, + QQmlImport::RecursionRestriction recursionRestriction) const { QQmlImportNamespace* ns = d->findQualifiedNamespace(type); if (ns) { @@ -629,17 +632,19 @@ bool QQmlImports::resolveType(const QHashedStringRef &type, return true; } if (type_return) { - if (d->resolveType(type,vmaj,vmin,type_return, errors)) { + if (d->resolveType(type, vmaj, vmin, type_return, errors, recursionRestriction)) { if (qmlImportTrace()) { #define RESOLVE_TYPE_DEBUG qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) \ << ')' << "::resolveType: " << type.toString() << " => " - if (type_return && *type_return && (*type_return)->isCompositeSingleton()) - RESOLVE_TYPE_DEBUG << (*type_return)->typeName() << ' ' << (*type_return)->sourceUrl() << " TYPE/URL-SINGLETON"; - else if (type_return && *type_return && (*type_return)->isComposite()) - RESOLVE_TYPE_DEBUG << (*type_return)->typeName() << ' ' << (*type_return)->sourceUrl() << " TYPE/URL"; - else if (type_return && *type_return) - RESOLVE_TYPE_DEBUG << (*type_return)->typeName() << " TYPE"; + if (type_return && type_return->isValid()) { + if (type_return->isCompositeSingleton()) + RESOLVE_TYPE_DEBUG << type_return->typeName() << ' ' << type_return->sourceUrl() << " TYPE/URL-SINGLETON"; + else if (type_return->isComposite()) + RESOLVE_TYPE_DEBUG << type_return->typeName() << ' ' << type_return->sourceUrl() << " TYPE/URL"; + else + RESOLVE_TYPE_DEBUG << type_return->typeName() << " TYPE"; + } #undef RESOLVE_TYPE_DEBUG } return true; @@ -704,19 +709,20 @@ QQmlDirScripts QQmlImportInstance::getVersionedScripts(const QQmlDirScripts &qml If the return pointer is 0, the corresponding search is not done. */ -bool QQmlImports::resolveType(QQmlImportNamespace* ns, const QHashedStringRef &type, - QQmlType** type_return, int *vmaj, int *vmin) const +bool QQmlImports::resolveType(QQmlImportNamespace *ns, const QHashedStringRef &type, + QQmlType *type_return, int *vmaj, int *vmin) const { - return ns->resolveType(d->typeLoader,type,vmaj,vmin,type_return); + return ns->resolveType(d->typeLoader, type, vmaj, vmin, type_return); } bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type, int *vmajor, int *vminor, - QQmlType** type_return, QString *base, bool *typeRecursionDetected) const + QQmlType* type_return, QString *base, bool *typeRecursionDetected, + QQmlImport::RecursionRestriction recursionRestriction) const { if (majversion >= 0 && minversion >= 0) { - QQmlType *t = QQmlMetaType::qmlType(type, uri, majversion, minversion); - if (t) { + QQmlType t = QQmlMetaType::qmlType(type, uri, majversion, minversion); + if (t.isValid()) { if (vmajor) *vmajor = majversion; if (vminor) *vminor = minversion; if (type_return) @@ -747,7 +753,7 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, if (resolveLocalUrl(*base, c.fileName) != componentUrl) continue; // failed attempt to access an internal type } - if (*base == componentUrl) { + if (recursionRestriction == QQmlImport::PreventRecursion && *base == componentUrl) { if (typeRecursionDetected) *typeRecursionDetected = true; continue; // no recursion @@ -766,11 +772,11 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, componentUrl = resolveLocalUrl(QString(url + candidate->typeName + dotqml_string), candidate->fileName); int major = vmajor ? *vmajor : -1; int minor = vminor ? *vminor : -1; - QQmlType *returnType = fetchOrCreateTypeForUrl(componentUrl, type, isCompositeSingleton, 0, + QQmlType returnType = fetchOrCreateTypeForUrl(componentUrl, type, isCompositeSingleton, 0, major, minor); if (type_return) *type_return = returnType; - return returnType != 0; + return returnType.isValid(); } } else if (!isLibrary) { QString qmlUrl; @@ -790,14 +796,14 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, } if (exists) { - if (base && (*base == qmlUrl)) { // no recursion + if (recursionRestriction == QQmlImport::PreventRecursion && base && (*base == qmlUrl)) { // no recursion if (typeRecursionDetected) *typeRecursionDetected = true; } else { - QQmlType *returnType = fetchOrCreateTypeForUrl(qmlUrl, type, false, 0); + QQmlType returnType = fetchOrCreateTypeForUrl(qmlUrl, type, false, 0); if (type_return) *type_return = returnType; - return returnType != 0; + return returnType.isValid(); } } } @@ -806,7 +812,8 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, } bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor, int *vminor, - QQmlType** type_return, QList<QQmlError> *errors) + QQmlType* type_return, QList<QQmlError> *errors, + QQmlImport::RecursionRestriction recursionRestriction) { QQmlImportNamespace *s = 0; int dot = type.indexOf(Dot); @@ -835,12 +842,12 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor, } QHashedStringRef unqualifiedtype = dot < 0 ? type : QHashedStringRef(type.constData()+dot+1, type.length()-dot-1); if (s) { - if (s->resolveType(typeLoader,unqualifiedtype,vmajor,vminor,type_return, &base, errors)) + if (s->resolveType(typeLoader, unqualifiedtype, vmajor, vminor, type_return, &base, errors, recursionRestriction)) return true; if (s->imports.count() == 1 && !s->imports.at(0)->isLibrary && type_return && s != &unqualifiedset) { // qualified, and only 1 url *type_return = fetchOrCreateTypeForUrl(resolveLocalUrl(s->imports.at(0)->url, unqualifiedtype.toString() + QLatin1String(".qml")), type, false, errors); - return (*type_return != 0); + return type_return->isValid(); } } @@ -857,14 +864,15 @@ QQmlImportInstance *QQmlImportNamespace::findImport(const QString &uri) const } bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type, - int *vmajor, int *vminor, QQmlType** type_return, - QString *base, QList<QQmlError> *errors) + int *vmajor, int *vminor, QQmlType* type_return, + QString *base, QList<QQmlError> *errors, + QQmlImport::RecursionRestriction recursionRestriction) { bool typeRecursionDetected = false; for (int i=0; i<imports.count(); ++i) { const QQmlImportInstance *import = imports.at(i); if (import->resolveType(typeLoader, type, vmajor, vminor, type_return, - base, &typeRecursionDetected)) { + base, &typeRecursionDetected, recursionRestriction)) { if (qmlCheckTypes()) { // check for type clashes for (int j = i+1; j<imports.count(); ++j) { @@ -966,8 +974,8 @@ static QVector<QStaticPlugin> makePlugins() // the list the first time called to only contain QML plugins: const auto staticPlugins = QPluginLoader::staticPlugins(); for (const QStaticPlugin &plugin : staticPlugins) { - if (plugin.metaData().value(QLatin1String("IID")).toString() - == QLatin1String(QQmlExtensionInterface_iid)) { + const QString iid = plugin.metaData().value(QLatin1String("IID")).toString(); + if (iid == QLatin1String(QQmlExtensionInterface_iid) || iid == QLatin1String(QQmlExtensionInterface_iid_old)) { plugins.append(plugin); } } @@ -1489,6 +1497,17 @@ bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix if (!url.endsWith(Slash) && !url.endsWith(Backslash)) url += Slash; + // ### For enum support, we are now adding the implicit import always (and earlier). Bail early + // if the implicit import has already been explicitly added, otherwise we can run into issues + // with duplicate imports + if (isImplicitImport) { + for (QList<QQmlImportInstance *>::const_iterator it = nameSpace->imports.constBegin(); + it != nameSpace->imports.constEnd(); ++it) { + if ((*it)->uri == importUri) + return true; + } + } + QQmlImportInstance *inserted = addImportToNamespace(nameSpace, importUri, url, vmaj, vmin, QV4::CompiledData::Import::ImportFile, errors, isImplicitImport); Q_ASSERT(inserted); diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h index 7c691a468c..0b4a0e6f80 100644 --- a/src/qml/qml/qqmlimport_p.h +++ b/src/qml/qml/qqmlimport_p.h @@ -70,6 +70,10 @@ class QQmlImportDatabase; class QQmlTypeLoader; class QQmlTypeLoaderQmldirContent; +namespace QQmlImport { + enum RecursionRestriction { PreventRecursion, AllowRecursion }; +} + struct QQmlImportInstance { QString uri; // e.g. QtQuick @@ -86,8 +90,9 @@ struct QQmlImportInstance static QQmlDirScripts getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin); bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type, - int *vmajor, int *vminor, QQmlType** type_return, - QString *base = 0, bool *typeRecursionDetected = 0) const; + int *vmajor, int *vminor, QQmlType* type_return, + QString *base = 0, bool *typeRecursionDetected = 0, + QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion) const; }; class QQmlImportNamespace @@ -101,8 +106,9 @@ public: QQmlImportInstance *findImport(const QString &uri) const; bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type, - int *vmajor, int *vminor, QQmlType** type_return, - QString *base = 0, QList<QQmlError> *errors = 0); + int *vmajor, int *vminor, QQmlType* type_return, + QString *base = 0, QList<QQmlError> *errors = 0, + QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion); // Prefix when used as a qualified import. Otherwise empty. QHashedString prefix; @@ -125,13 +131,14 @@ public: QUrl baseUrl() const; bool resolveType(const QHashedStringRef &type, - QQmlType** type_return, + QQmlType *type_return, int *version_major, int *version_minor, - QQmlImportNamespace** ns_return, - QList<QQmlError> *errors = 0) const; - bool resolveType(QQmlImportNamespace*, + QQmlImportNamespace **ns_return, + QList<QQmlError> *errors = 0, + QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion) const; + bool resolveType(QQmlImportNamespace *, const QHashedStringRef& type, - QQmlType** type_return, int *version_major, int *version_minor) const; + QQmlType *type_return, int *version_major, int *version_minor) const; bool addImplicitImport(QQmlImportDatabase *importDb, QList<QQmlError> *errors); diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index aec85442b3..037b82cdff 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -111,6 +111,7 @@ QQmlJavaScriptExpression::~QQmlJavaScriptExpression() clearActiveGuards(); clearPermanentGuards(); + clearError(); if (m_scopeObject.isT2()) // notify DeleteWatcher of our deletion. m_scopeObject.asT2()->_s = 0; @@ -289,7 +290,7 @@ void QQmlPropertyCapture::captureProperty(QQmlNotifier *n, Duration duration) \a n is in the signal index range (see QObjectPrivate::signalIndex()). */ -void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n, Duration duration) +void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n, Duration duration, bool doNotify) { if (watcher->wasDeleted()) return; @@ -325,7 +326,7 @@ void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n, Duration dur Q_ASSERT(g->isConnected(o, n)); } else { g = QQmlJavaScriptExpressionGuard::New(expression, engine); - g->connect(o, n, engine); + g->connect(o, n, engine, doNotify); } if (duration == Permanently) @@ -355,7 +356,7 @@ void QQmlPropertyCapture::registerQmlDependencies(QV4::Heap::QmlContext *context QV4::Heap::QQmlContextWrapper *wrapper = context->qml(); QQmlContextData *qmlContext = wrapper->context->contextData(); - const QV4::CompiledData::LEUInt32 *idObjectDependency = compiledFunction->qmlIdObjectDependencyTable(); + const quint32_le *idObjectDependency = compiledFunction->qmlIdObjectDependencyTable(); const int idObjectDependencyCount = compiledFunction->nDependingIdObjects; for (int i = 0; i < idObjectDependencyCount; ++i, ++idObjectDependency) { Q_ASSERT(int(*idObjectDependency) < qmlContext->idValueCount); @@ -364,7 +365,7 @@ void QQmlPropertyCapture::registerQmlDependencies(QV4::Heap::QmlContext *context } Q_ASSERT(qmlContext->contextObject); - const QV4::CompiledData::LEUInt32 *contextPropertyDependency = compiledFunction->qmlContextPropertiesDependencyTable(); + const quint32_le *contextPropertyDependency = compiledFunction->qmlContextPropertiesDependencyTable(); const int contextPropertyDependencyCount = compiledFunction->nDependingContextProperties; for (int i = 0; i < contextPropertyDependencyCount; ++i) { const int propertyIndex = *contextPropertyDependency++; @@ -374,7 +375,7 @@ void QQmlPropertyCapture::registerQmlDependencies(QV4::Heap::QmlContext *context } QObject *scopeObject = wrapper->scopeObject; - const QV4::CompiledData::LEUInt32 *scopePropertyDependency = compiledFunction->qmlScopePropertiesDependencyTable(); + const quint32_le *scopePropertyDependency = compiledFunction->qmlScopePropertiesDependencyTable(); const int scopePropertyDependencyCount = compiledFunction->nDependingScopeProperties; for (int i = 0; i < scopePropertyDependencyCount; ++i) { const int propertyIndex = *scopePropertyDependency++; @@ -466,7 +467,12 @@ void QQmlJavaScriptExpression::setupFunction(QV4::ExecutionContext *qmlContext, return; m_qmlScope.set(qmlContext->engine(), *qmlContext); m_v4Function = f; - m_compilationUnit = m_v4Function->compilationUnit; + setCompilationUnit(m_v4Function->compilationUnit); +} + +void QQmlJavaScriptExpression::setCompilationUnit(QV4::CompiledData::CompilationUnit *compilationUnit) +{ + m_compilationUnit = compilationUnit; } void QQmlJavaScriptExpression::clearActiveGuards() diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h index 4d4c2e6c9f..1cb6d7bfd1 100644 --- a/src/qml/qml/qqmljavascriptexpression_p.h +++ b/src/qml/qml/qqmljavascriptexpression_p.h @@ -161,13 +161,7 @@ protected: } void setupFunction(QV4::ExecutionContext *qmlContext, QV4::Function *f); - -private: - friend class QQmlContextData; - friend class QQmlPropertyCapture; - friend void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *, void **); - - QQmlDelayedError *m_error; + void setCompilationUnit(QV4::CompiledData::CompilationUnit *compilationUnit); // We store some flag bits in the following flag pointers. // activeGuards:flag1 - notifyOnValueChanged @@ -176,6 +170,14 @@ private: QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> activeGuards; QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> permanentGuards; +private: + friend class QQmlContextData; + friend class QQmlPropertyCapture; + friend void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *, void **); + friend class QQmlTranslationBinding; + + QQmlDelayedError *m_error; + QQmlContextData *m_context; QQmlJavaScriptExpression **m_prevExpression; QQmlJavaScriptExpression *m_nextExpression; @@ -205,7 +207,7 @@ public: static void registerQmlDependencies(QV4::Heap::QmlContext *context, const QV4::ExecutionEngine *engine, const QV4::CompiledData::Function *compiledFunction); void captureProperty(QQmlNotifier *, Duration duration = OnlyOnce); - void captureProperty(QObject *, int, int, Duration duration = OnlyOnce); + void captureProperty(QObject *, int, int, Duration duration = OnlyOnce, bool doNotify = true); QQmlEngine *engine; QQmlJavaScriptExpression *expression; diff --git a/src/qml/qml/qqmllist.cpp b/src/qml/qml/qqmllist.cpp index 2c71293363..71be2e82a3 100644 --- a/src/qml/qml/qqmllist.cpp +++ b/src/qml/qml/qqmllist.cpp @@ -148,7 +148,7 @@ QQmlListReference::QQmlListReference(QObject *object, const char *property, QQml d = new QQmlListReferencePrivate; d->object = object; - d->elementType = p?p->rawMetaObjectForType(listType):QQmlMetaType::qmlType(listType)->baseMetaObject(); + d->elementType = p ? p->rawMetaObjectForType(listType) : QQmlMetaType::qmlType(listType).baseMetaObject(); d->propertyType = data->propType(); void *args[] = { &d->property, 0 }; diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index eebf6ccd1e..3dfdbf572a 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -69,18 +69,20 @@ struct QQmlMetaTypeData { QQmlMetaTypeData(); ~QQmlMetaTypeData(); - QList<QQmlType *> types; - typedef QHash<int, QQmlType *> Ids; + void registerType(QQmlTypePrivate *priv); + QList<QQmlType> types; + QSet<QQmlType> undeletableTypes; + typedef QHash<int, QQmlTypePrivate *> Ids; Ids idToType; - typedef QHash<QHashedStringRef,QQmlType *> Names; + typedef QHash<QHashedStringRef, QQmlTypePrivate *> Names; Names nameToType; - typedef QHash<QUrl, QQmlType *> Files; //For file imported composite types only + typedef QHash<QUrl, QQmlTypePrivate *> Files; //For file imported composite types only Files urlToType; Files urlToNonFileImportType; // For non-file imported composite and composite // singleton types. This way we can locate any // of them by url, even if it was registered as // a module via QQmlPrivate::RegisterCompositeType - typedef QHash<const QMetaObject *, QQmlType *> MetaObjects; + typedef QHash<const QMetaObject *, QQmlTypePrivate *> MetaObjects; MetaObjects metaObjectToType; typedef QHash<int, QQmlMetaType::StringConverter> StringConverters; StringConverters stringConverters; @@ -110,6 +112,12 @@ struct QQmlMetaTypeData QString typeRegistrationNamespace; QStringList typeRegistrationFailures; + + QHash<int, int> qmlLists; + + QHash<const QMetaObject *, QQmlPropertyCache *> propertyCaches; + QQmlPropertyCache *propertyCache(const QMetaObject *metaObject); + QQmlPropertyCache *propertyCache(const QQmlType &type, int minorVersion); }; class QQmlTypeModulePrivate @@ -126,10 +134,11 @@ public: int maxMinorVersion; bool locked; - void add(QQmlType *); + void add(QQmlTypePrivate *); + void remove(const QQmlTypePrivate *type); - QStringHash<QList<QQmlType *> > typeHash; - QList<QQmlType *> types; + typedef QStringHash<QList<QQmlTypePrivate *> > TypeHash; + TypeHash typeHash; }; Q_GLOBAL_STATIC(QQmlMetaTypeData, metaTypeData) @@ -146,23 +155,26 @@ QQmlMetaTypeData::QQmlMetaTypeData() QQmlMetaTypeData::~QQmlMetaTypeData() { - for (int i = 0; i < types.count(); ++i) - delete types.at(i); - 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(); } class QQmlTypePrivate { + Q_DISABLE_COPY(QQmlTypePrivate) public: QQmlTypePrivate(QQmlType::RegistrationType type); ~QQmlTypePrivate(); void init() const; - void initEnums() const; + void initEnums(const QQmlPropertyCache *cache = 0) const; void insertEnums(const QMetaObject *metaObject) const; + void insertEnumsFromPropertyCache(const QQmlPropertyCache *cache) const; + QAtomicInt refCount; QQmlType::RegistrationType regType; struct QQmlCppTypeData @@ -207,7 +219,7 @@ public: int listId; int revision; mutable bool containsRevisionedAttributes; - mutable QQmlType *superType; + mutable QQmlType superType; const QMetaObject *baseMetaObject; int index; @@ -220,8 +232,32 @@ public: mutable QList<QStringHash<int>*> scopedEnums; static QHash<const QMetaObject *, int> attachedPropertyIds; + + struct PropertyCacheByMinorVersion + { + PropertyCacheByMinorVersion() : cache(Q_NULLPTR), minorVersion(-1) {} + explicit PropertyCacheByMinorVersion(QQmlPropertyCache *pc, int ver) : cache(pc), minorVersion(ver) {} + QQmlPropertyCachePtr cache; + int minorVersion; + }; + QVector<PropertyCacheByMinorVersion> propertyCaches; + QQmlPropertyCache *propertyCacheForMinorVersion(int minorVersion) const; + void setPropertyCacheForMinorVersion(int minorVersion, QQmlPropertyCache *cache); }; +void QQmlMetaTypeData::registerType(QQmlTypePrivate *priv) +{ + for (int i = 0; i < types.count(); ++i) { + if (!types.at(i).isValid()) { + types[i] = QQmlType(priv); + priv->index = i; + return; + } + } + types.append(QQmlType(priv)); + priv->index = types.count() - 1; +} + void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e) { if (scriptCallback && scriptApi(e).isUndefined()) { @@ -277,8 +313,8 @@ QJSValue QQmlType::SingletonInstanceInfo::scriptApi(QQmlEngine *e) const QHash<const QMetaObject *, int> QQmlTypePrivate::attachedPropertyIds; QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type) -: regType(type), iid(0), typeId(0), listId(0), revision(0), - containsRevisionedAttributes(false), superType(0), baseMetaObject(0), +: refCount(1), regType(type), iid(0), typeId(0), listId(0), revision(0), + containsRevisionedAttributes(false), baseMetaObject(0), index(-1), isSetup(false), isEnumSetup(false), haveSuperType(false) { switch (type) { @@ -331,21 +367,23 @@ QQmlTypePrivate::~QQmlTypePrivate() } } -QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface) -: d(new QQmlTypePrivate(InterfaceType)) +QQmlType::QQmlType(QQmlMetaTypeData *data, const QQmlPrivate::RegisterInterface &interface) + : d(new QQmlTypePrivate(InterfaceType)) { d->iid = interface.iid; d->typeId = interface.typeId; d->listId = interface.listId; - d->index = index; d->isSetup = true; d->version_maj = 0; d->version_min = 0; + data->registerType(d); } -QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterSingletonType &type) -: d(new QQmlTypePrivate(SingletonType)) +QQmlType::QQmlType(QQmlMetaTypeData *data, const QString &elementName, const QQmlPrivate::RegisterSingletonType &type) + : d(new QQmlTypePrivate(SingletonType)) { + data->registerType(d); + d->elementName = elementName; d->module = QString::fromUtf8(type.uri); @@ -361,8 +399,6 @@ QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::Reg d->revision = type.revision; } - d->index = index; - d->extraData.sd->singletonInstanceInfo = new SingletonInstanceInfo; d->extraData.sd->singletonInstanceInfo->scriptCallback = type.scriptApi; d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.qobjectApi; @@ -371,25 +407,27 @@ QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::Reg = (type.qobjectApi && type.version >= 1) ? type.instanceMetaObject : 0; } -QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterCompositeSingletonType &type) - : d(new QQmlTypePrivate(CompositeSingletonType)) +QQmlType::QQmlType(QQmlMetaTypeData *data, const QString &elementName, const QQmlPrivate::RegisterCompositeSingletonType &type) + : d(new QQmlTypePrivate(CompositeSingletonType)) { + data->registerType(d); + d->elementName = elementName; d->module = QString::fromUtf8(type.uri); d->version_maj = type.versionMajor; d->version_min = type.versionMinor; - d->index = index; - d->extraData.sd->singletonInstanceInfo = new SingletonInstanceInfo; d->extraData.sd->singletonInstanceInfo->url = type.url; d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName); } -QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterType &type) -: d(new QQmlTypePrivate(CppType)) +QQmlType::QQmlType(QQmlMetaTypeData *data, const QString &elementName, const QQmlPrivate::RegisterType &type) + : d(new QQmlTypePrivate(CppType)) { + data->registerType(d); + d->elementName = elementName; d->module = QString::fromUtf8(type.uri); @@ -408,7 +446,7 @@ QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::Reg if (d->extraData.cd->attachedPropertiesType) { QHash<const QMetaObject *, int>::Iterator iter = d->attachedPropertyIds.find(d->baseMetaObject); if (iter == d->attachedPropertyIds.end()) - iter = d->attachedPropertyIds.insert(d->baseMetaObject, index); + iter = d->attachedPropertyIds.insert(d->baseMetaObject, d->index); d->extraData.cd->attachedPropertiesId = *iter; } else { d->extraData.cd->attachedPropertiesId = -1; @@ -418,16 +456,16 @@ QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::Reg d->extraData.cd->propertyValueInterceptorCast = type.valueInterceptorCast; d->extraData.cd->extFunc = type.extensionObjectCreate; d->extraData.cd->customParser = type.customParser; - d->index = index; if (type.extensionMetaObject) d->extraData.cd->extMetaObject = type.extensionMetaObject; } -QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterCompositeType &type) -: d(new QQmlTypePrivate(CompositeType)) +QQmlType::QQmlType(QQmlMetaTypeData *data, const QString &elementName, const QQmlPrivate::RegisterCompositeType &type) + : d(new QQmlTypePrivate(CompositeType)) { - d->index = index; + data->registerType(d); + d->elementName = elementName; d->module = QString::fromUtf8(type.uri); @@ -437,44 +475,88 @@ QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::Reg d->extraData.fd->url = type.url; } +QQmlType::QQmlType() + : d(0) +{ +} + +QQmlType::QQmlType(const QQmlType &other) + : d(other.d) +{ + if (d) + d->refCount.ref(); +} + +QQmlType &QQmlType::operator =(const QQmlType &other) +{ + if (d != other.d) { + if (d && !d->refCount.deref()) + delete d; + d = other.d; + if (d) + d->refCount.ref(); + } + return *this; +} + +QQmlType::QQmlType(QQmlTypePrivate *priv) + : d(priv) +{ + if (d) + d->refCount.ref(); +} + QQmlType::~QQmlType() { - delete d; + if (d && !d->refCount.deref()) + delete d; } -const QHashedString &QQmlType::module() const +QHashedString QQmlType::module() const { + if (!d) + return QHashedString(); return d->module; } int QQmlType::majorVersion() const { + if (!d) + return -1; return d->version_maj; } int QQmlType::minorVersion() const { + if (!d) + return -1; return d->version_min; } bool QQmlType::availableInVersion(int vmajor, int vminor) const { Q_ASSERT(vmajor >= 0 && vminor >= 0); + if (!d) + return false; return vmajor == d->version_maj && vminor >= d->version_min; } bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const { Q_ASSERT(vmajor >= 0 && vminor >= 0); + if (!d) + return false; return module == d->module && vmajor == d->version_maj && vminor >= d->version_min; } // returns the nearest _registered_ super class -QQmlType *QQmlType::superType() const +QQmlType QQmlType::superType() const { + if (!d) + return QQmlType(); if (!d->haveSuperType && d->baseMetaObject) { const QMetaObject *mo = d->baseMetaObject->superClass(); - while (mo && !d->superType) { + while (mo && !d->superType.isValid()) { d->superType = QQmlMetaType::qmlType(mo, d->module, d->version_maj, d->version_min); mo = mo->superClass(); } @@ -484,88 +566,30 @@ QQmlType *QQmlType::superType() const return d->superType; } -QQmlType *QQmlType::resolveCompositeBaseType(QQmlEnginePrivate *engine) const +QQmlType QQmlType::resolveCompositeBaseType(QQmlEnginePrivate *engine) const { Q_ASSERT(isComposite()); - if (!engine) - return 0; + if (!engine || !d) + return QQmlType(); QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(sourceUrl()), QQmlRefPointer<QQmlTypeData>::Adopt); if (td.isNull() || !td->isComplete()) - return 0; + return QQmlType(); QV4::CompiledData::CompilationUnit *compilationUnit = td->compilationUnit(); const QMetaObject *mo = compilationUnit->rootPropertyCache()->firstCppMetaObject(); return QQmlMetaType::qmlType(mo); } -int QQmlType::resolveCompositeEnumValue(QQmlEnginePrivate *engine, const QString &name, bool *ok) const -{ - Q_ASSERT(isComposite()); - *ok = false; - QQmlType *type = resolveCompositeBaseType(engine); - if (!type) - return -1; - return type->enumValue(engine, name, ok); -} - -int QQmlType::resolveCompositeScopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const -{ - Q_ASSERT(isComposite()); - *ok = false; - QQmlType *type = resolveCompositeBaseType(engine); - if (!type) - return -1; - return type->scopedEnumIndex(engine, name, ok); -} - -int QQmlType::resolveCompositeScopedEnumIndex(QQmlEnginePrivate *engine, const QString &name, bool *ok) const -{ - Q_ASSERT(isComposite()); - *ok = false; - QQmlType *type = resolveCompositeBaseType(engine); - if (!type) - return -1; - return type->scopedEnumIndex(engine, name, ok); -} - - -int QQmlType::resolveCompositeScopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *name, bool *ok) const -{ - Q_ASSERT(isComposite()); - *ok = false; - QQmlType *type = resolveCompositeBaseType(engine); - if (!type) - return -1; - return type->scopedEnumValue(engine, index, name, ok); -} - -int QQmlType::resolveCompositeScopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &name, bool *ok) const +QQmlPropertyCache *QQmlType::compositePropertyCache(QQmlEnginePrivate *engine) const { + // similar logic to resolveCompositeBaseType Q_ASSERT(isComposite()); - *ok = false; - QQmlType *type = resolveCompositeBaseType(engine); - if (!type) - return -1; - return type->scopedEnumValue(engine, index, name, ok); -} - -int QQmlType::resolveCompositeScopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &scopedName, const QByteArray &name, bool *ok) const -{ - Q_ASSERT(isComposite()); - *ok = false; - QQmlType *type = resolveCompositeBaseType(engine); - if (!type) - return -1; - return type->scopedEnumValue(engine, scopedName, name, ok); -} - -int QQmlType::resolveCompositeScopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &scopedName, const QStringRef &name, bool *ok) const -{ - Q_ASSERT(isComposite()); - *ok = false; - QQmlType *type = resolveCompositeBaseType(engine); - if (!type) - return -1; - return type->scopedEnumValue(engine, scopedName, name, ok); + if (!engine) + return 0; + QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(sourceUrl()), QQmlRefPointer<QQmlTypeData>::Adopt); + if (td.isNull() || !td->isComplete()) + return 0; + QV4::CompiledData::CompilationUnit *compilationUnit = td->compilationUnit(); + return compilationUnit->rootPropertyCache(); } static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo, @@ -685,18 +709,18 @@ void QQmlTypePrivate::init() const mo = mo->d.superdata; while(mo) { - QQmlType *t = metaTypeData()->metaObjectToType.value(mo); + QQmlTypePrivate *t = metaTypeData()->metaObjectToType.value(mo); if (t) { - if (t->d->regType == QQmlType::CppType) { - if (t->d->extraData.cd->extFunc) { + if (t->regType == QQmlType::CppType) { + if (t->extraData.cd->extFunc) { QMetaObjectBuilder builder; - clone(builder, t->d->extraData.cd->extMetaObject, t->d->baseMetaObject, baseMetaObject); + clone(builder, t->extraData.cd->extMetaObject, t->baseMetaObject, baseMetaObject); builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); QMetaObject *mmo = builder.toMetaObject(); mmo->d.superdata = baseMetaObject; if (!metaObjects.isEmpty()) metaObjects.constLast().metaObject->d.superdata = mmo; - QQmlProxyMetaObject::ProxyData data = { mmo, t->d->extraData.cd->extFunc, 0, 0 }; + QQmlProxyMetaObject::ProxyData data = { mmo, t->extraData.cd->extFunc, 0, 0 }; metaObjects << data; } } @@ -734,7 +758,7 @@ void QQmlTypePrivate::init() const lock.unlock(); } -void QQmlTypePrivate::initEnums() const +void QQmlTypePrivate::initEnums(const QQmlPropertyCache *cache) const { if (isEnumSetup) return; @@ -743,6 +767,8 @@ void QQmlTypePrivate::initEnums() const QMutexLocker lock(metaTypeDataLock()); if (isEnumSetup) return; + if (cache) + insertEnumsFromPropertyCache(cache); if (baseMetaObject) // could be singleton type without metaobject insertEnums(baseMetaObject); @@ -781,23 +807,72 @@ void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const } } +void QQmlTypePrivate::insertEnumsFromPropertyCache(const QQmlPropertyCache *cache) const +{ + const QMetaObject *cppMetaObject = cache->firstCppMetaObject(); + + while (cache && cache->metaObject() != cppMetaObject) { + QStringHash<int> *scoped = new QStringHash<int>(); + + int count = cache->qmlEnumCount(); + for (int ii = 0; ii < count; ++ii) { + QQmlEnumData *enumData = cache->qmlEnum(ii); + + for (int jj = 0; jj < enumData->values.count(); ++jj) { + const QQmlEnumValue &value = enumData->values.at(jj); + enums.insert(value.namedValue, value.value); + scoped->insert(value.namedValue, value.value); + } + scopedEnums << scoped; + scopedEnumIndex.insert(enumData->name, scopedEnums.count()-1); + } + cache = cache->parent(); + } + insertEnums(cppMetaObject); +} + + +QQmlPropertyCache *QQmlTypePrivate::propertyCacheForMinorVersion(int minorVersion) const +{ + for (int i = 0; i < propertyCaches.count(); ++i) + if (propertyCaches.at(i).minorVersion == minorVersion) + return propertyCaches.at(i).cache; + return Q_NULLPTR; +} + +void QQmlTypePrivate::setPropertyCacheForMinorVersion(int minorVersion, QQmlPropertyCache *cache) +{ + for (int i = 0; i < propertyCaches.count(); ++i) { + if (propertyCaches.at(i).minorVersion == minorVersion) { + propertyCaches[i].cache = cache; + return; + } + } + propertyCaches.append(PropertyCacheByMinorVersion(cache, minorVersion)); +} + QByteArray QQmlType::typeName() const { - if (d->regType == SingletonType || d->regType == CompositeSingletonType) - return d->extraData.sd->singletonInstanceInfo->typeName.toUtf8(); - else if (d->baseMetaObject) - return d->baseMetaObject->className(); - else - return QByteArray(); + if (d) { + if (d->regType == SingletonType || d->regType == CompositeSingletonType) + return d->extraData.sd->singletonInstanceInfo->typeName.toUtf8(); + else if (d->baseMetaObject) + return d->baseMetaObject->className(); + } + return QByteArray(); } -const QString &QQmlType::elementName() const +QString QQmlType::elementName() const { + if (!d) + return QString(); return d->elementName; } -const QString &QQmlType::qmlTypeName() const +QString QQmlType::qmlTypeName() const { + if (!d) + return QString(); if (d->name.isEmpty()) { if (!d->module.isEmpty()) d->name = static_cast<QString>(d->module) + QLatin1Char('/') + d->elementName; @@ -810,7 +885,7 @@ const QString &QQmlType::qmlTypeName() const QObject *QQmlType::create() const { - if (!isCreatable()) + if (!d || !isCreatable()) return 0; d->init(); @@ -826,7 +901,7 @@ QObject *QQmlType::create() const void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) const { - if (!isCreatable()) + if (!d || !isCreatable()) return; d->init(); @@ -843,6 +918,8 @@ void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) con QQmlType::SingletonInstanceInfo *QQmlType::singletonInstanceInfo() const { + if (!d) + return 0; if (d->regType != SingletonType && d->regType != CompositeSingletonType) return 0; return d->extraData.sd->singletonInstanceInfo; @@ -850,6 +927,8 @@ QQmlType::SingletonInstanceInfo *QQmlType::singletonInstanceInfo() const QQmlCustomParser *QQmlType::customParser() const { + if (!d) + return 0; if (d->regType != CppType) return 0; return d->extraData.cd->customParser; @@ -857,32 +936,34 @@ QQmlCustomParser *QQmlType::customParser() const QQmlType::CreateFunc QQmlType::createFunction() const { - if (d->regType != CppType) + if (!d || d->regType != CppType) return 0; return d->extraData.cd->newFunc; } QString QQmlType::noCreationReason() const { - if (d->regType != CppType) + if (!d || d->regType != CppType) return QString(); return d->extraData.cd->noCreationReason; } int QQmlType::createSize() const { - if (d->regType != CppType) + if (!d || d->regType != CppType) return 0; return d->extraData.cd->allocationSize; } bool QQmlType::isCreatable() const { - return d->regType == CppType && d->extraData.cd->newFunc; + return d && d->regType == CppType && d->extraData.cd->newFunc; } bool QQmlType::isExtendedType() const { + if (!d) + return false; d->init(); return !d->metaObjects.isEmpty(); @@ -890,36 +971,38 @@ bool QQmlType::isExtendedType() const bool QQmlType::isSingleton() const { - return d->regType == SingletonType || d->regType == CompositeSingletonType; + return d && (d->regType == SingletonType || d->regType == CompositeSingletonType); } bool QQmlType::isInterface() const { - return d->regType == InterfaceType; + return d && d->regType == InterfaceType; } bool QQmlType::isComposite() const { - return d->regType == CompositeType || d->regType == CompositeSingletonType; + return d && (d->regType == CompositeType || d->regType == CompositeSingletonType); } bool QQmlType::isCompositeSingleton() const { - return d->regType == CompositeSingletonType; + return d && d->regType == CompositeSingletonType; } int QQmlType::typeId() const { - return d->typeId; + return d ? d->typeId : -1; } int QQmlType::qListTypeId() const { - return d->listId; + return d ? d->listId : -1; } const QMetaObject *QQmlType::metaObject() const { + if (!d) + return 0; d->init(); if (d->metaObjects.isEmpty()) @@ -931,11 +1014,13 @@ const QMetaObject *QQmlType::metaObject() const const QMetaObject *QQmlType::baseMetaObject() const { - return d->baseMetaObject; + return d ? d->baseMetaObject : 0; } bool QQmlType::containsRevisionedAttributes() const { + if (!d) + return false; d->init(); return d->containsRevisionedAttributes; @@ -943,29 +1028,33 @@ bool QQmlType::containsRevisionedAttributes() const int QQmlType::metaObjectRevision() const { - return d->revision; + return d ? d->revision : -1; } QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction(QQmlEnginePrivate *engine) const { + if (!d) + return 0; if (d->regType == CppType) return d->extraData.cd->attachedPropertiesFunc; - QQmlType *base = 0; + QQmlType base; if (d->regType == CompositeType) base = resolveCompositeBaseType(engine); - return base ? base->attachedPropertiesFunction(engine) : 0; + return base.attachedPropertiesFunction(engine); } const QMetaObject *QQmlType::attachedPropertiesType(QQmlEnginePrivate *engine) const { + if (!d) + return 0; if (d->regType == CppType) return d->extraData.cd->attachedPropertiesType; - QQmlType *base = 0; + QQmlType base; if (d->regType == CompositeType) base = resolveCompositeBaseType(engine); - return base ? base->attachedPropertiesType(engine) : 0; + return base.attachedPropertiesType(engine); } /* @@ -975,70 +1064,75 @@ Qt 4.7 and QtQuick 1.0). */ int QQmlType::attachedPropertiesId(QQmlEnginePrivate *engine) const { + if (!d) + return -1; if (d->regType == CppType) return d->extraData.cd->attachedPropertiesId; - QQmlType *base = 0; + QQmlType base; if (d->regType == CompositeType) base = resolveCompositeBaseType(engine); - return base ? base->attachedPropertiesId(engine) : 0; + return base.attachedPropertiesId(engine); } int QQmlType::parserStatusCast() const { - if (d->regType != CppType) + if (!d || d->regType != CppType) return -1; return d->extraData.cd->parserStatusCast; } int QQmlType::propertyValueSourceCast() const { - if (d->regType != CppType) + if (!d || d->regType != CppType) return -1; return d->extraData.cd->propertyValueSourceCast; } int QQmlType::propertyValueInterceptorCast() const { - if (d->regType != CppType) + if (!d || d->regType != CppType) return -1; return d->extraData.cd->propertyValueInterceptorCast; } const char *QQmlType::interfaceIId() const { - if (d->regType != InterfaceType) + if (!d || d->regType != InterfaceType) return 0; return d->iid; } int QQmlType::index() const { - return d->index; + return d ? d->index : -1; } QUrl QQmlType::sourceUrl() const { - if (d->regType == CompositeType) - return d->extraData.fd->url; - else if (d->regType == CompositeSingletonType) - return d->extraData.sd->singletonInstanceInfo->url; - else - return QUrl(); + if (d) { + if (d->regType == CompositeType) + return d->extraData.fd->url; + else if (d->regType == CompositeSingletonType) + return d->extraData.sd->singletonInstanceInfo->url; + } + return QUrl(); } int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedStringRef &name, bool *ok) const { Q_ASSERT(ok); - if (isComposite()) - return resolveCompositeEnumValue(engine, name.toString(), ok); - *ok = true; + if (d) { + const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : 0; - d->initEnums(); + *ok = true; - int *rv = d->enums.value(name); - if (rv) - return *rv; + d->initEnums(cache); + + int *rv = d->enums.value(name); + if (rv) + return *rv; + } *ok = false; return -1; @@ -1047,15 +1141,17 @@ int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedStringRef &name, int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedCStringRef &name, bool *ok) const { Q_ASSERT(ok); - if (isComposite()) - return resolveCompositeEnumValue(engine, name.toUtf16(), ok); - *ok = true; + if (d) { + const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : 0; - d->initEnums(); + *ok = true; - int *rv = d->enums.value(name); - if (rv) - return *rv; + d->initEnums(cache); + + int *rv = d->enums.value(name); + if (rv) + return *rv; + } *ok = false; return -1; @@ -1064,15 +1160,16 @@ int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedCStringRef &name int QQmlType::enumValue(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const { Q_ASSERT(ok); - if (isComposite()) - return resolveCompositeEnumValue(engine, name->toQString(), ok); - *ok = true; + if (d) { + const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : 0; + *ok = true; - d->initEnums(); + d->initEnums(cache); - int *rv = d->enums.value(name); - if (rv) - return *rv; + int *rv = d->enums.value(name); + if (rv) + return *rv; + } *ok = false; return -1; @@ -1081,15 +1178,16 @@ int QQmlType::enumValue(QQmlEnginePrivate *engine, const QV4::String *name, bool int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const { Q_ASSERT(ok); - if (isComposite()) - return resolveCompositeScopedEnumIndex(engine, name, ok); - *ok = true; + if (d) { + const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : 0; + *ok = true; - d->initEnums(); + d->initEnums(cache); - int *rv = d->scopedEnumIndex.value(name); - if (rv) - return *rv; + int *rv = d->scopedEnumIndex.value(name); + if (rv) + return *rv; + } *ok = false; return -1; @@ -1098,15 +1196,16 @@ int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *name int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QString &name, bool *ok) const { Q_ASSERT(ok); - if (isComposite()) - return resolveCompositeScopedEnumIndex(engine, name, ok); - *ok = true; + if (d) { + const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : 0; + *ok = true; - d->initEnums(); + d->initEnums(cache); - int *rv = d->scopedEnumIndex.value(name); - if (rv) - return *rv; + int *rv = d->scopedEnumIndex.value(name); + if (rv) + return *rv; + } *ok = false; return -1; @@ -1114,15 +1213,16 @@ int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QString &name, bo int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *name, bool *ok) const { + Q_UNUSED(engine) Q_ASSERT(ok); - if (isComposite()) - return resolveCompositeScopedEnumValue(engine, index, name, ok); *ok = true; - Q_ASSERT(index > -1 && index < d->scopedEnums.count()); - int *rv = d->scopedEnums.at(index)->value(name); - if (rv) - return *rv; + if (d) { + Q_ASSERT(index > -1 && index < d->scopedEnums.count()); + int *rv = d->scopedEnums.at(index)->value(name); + if (rv) + return *rv; + } *ok = false; return -1; @@ -1130,15 +1230,16 @@ int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::S int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &name, bool *ok) const { + Q_UNUSED(engine) Q_ASSERT(ok); - if (isComposite()) - return resolveCompositeScopedEnumValue(engine, index, name, ok); *ok = true; - Q_ASSERT(index > -1 && index < d->scopedEnums.count()); - int *rv = d->scopedEnums.at(index)->value(name); - if (rv) - return *rv; + if (d) { + Q_ASSERT(index > -1 && index < d->scopedEnums.count()); + int *rv = d->scopedEnums.at(index)->value(name); + if (rv) + return *rv; + } *ok = false; return -1; @@ -1147,19 +1248,20 @@ int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QStrin int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &scopedEnumName, const QByteArray &name, bool *ok) const { Q_ASSERT(ok); - if (isComposite()) - return resolveCompositeScopedEnumValue(engine, scopedEnumName, name, ok); - *ok = true; - - d->initEnums(); - - int *rv = d->scopedEnumIndex.value(QHashedCStringRef(scopedEnumName.constData(), scopedEnumName.length())); - if (rv) { - int index = *rv; - Q_ASSERT(index > -1 && index < d->scopedEnums.count()); - rv = d->scopedEnums.at(index)->value(QHashedCStringRef(name.constData(), name.length())); - if (rv) - return *rv; + if (d) { + const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : 0; + *ok = true; + + d->initEnums(cache); + + int *rv = d->scopedEnumIndex.value(QHashedCStringRef(scopedEnumName.constData(), scopedEnumName.length())); + if (rv) { + int index = *rv; + Q_ASSERT(index > -1 && index < d->scopedEnums.count()); + rv = d->scopedEnums.at(index)->value(QHashedCStringRef(name.constData(), name.length())); + if (rv) + return *rv; + } } *ok = false; @@ -1169,25 +1271,59 @@ int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &scope int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &scopedEnumName, const QStringRef &name, bool *ok) const { Q_ASSERT(ok); - if (isComposite()) - return resolveCompositeScopedEnumValue(engine, scopedEnumName, name, ok); - *ok = true; - - d->initEnums(); - - int *rv = d->scopedEnumIndex.value(QHashedStringRef(scopedEnumName)); - if (rv) { - int index = *rv; - Q_ASSERT(index > -1 && index < d->scopedEnums.count()); - rv = d->scopedEnums.at(index)->value(QHashedStringRef(name)); - if (rv) - return *rv; + if (d) { + const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : 0; + *ok = true; + + d->initEnums(cache); + + int *rv = d->scopedEnumIndex.value(QHashedStringRef(scopedEnumName)); + if (rv) { + int index = *rv; + Q_ASSERT(index > -1 && index < d->scopedEnums.count()); + rv = d->scopedEnums.at(index)->value(QHashedStringRef(name)); + if (rv) + return *rv; + } } *ok = false; return -1; } +void QQmlType::refHandle(QQmlTypePrivate *priv) +{ + if (priv) + priv->refCount.ref(); +} + +void QQmlType::derefHandle(QQmlTypePrivate *priv) +{ + if (priv && !priv->refCount.deref()) + delete priv; +} + +namespace { +template <typename QQmlTypeContainer> +void removeQQmlTypePrivate(QQmlTypeContainer &container, const QQmlTypePrivate *reference) +{ + for (typename QQmlTypeContainer::iterator it = container.begin(); it != container.end();) { + if (*it == reference) + it = container.erase(it); + else + ++it; + } +} + +struct IsQQmlTypePrivate +{ + const QQmlTypePrivate *reference; + explicit IsQQmlTypePrivate(const QQmlTypePrivate *ref) : reference(ref) {} + + bool operator()(const QQmlTypePrivate *priv) const { return reference == priv; } +}; +} + QQmlTypeModule::QQmlTypeModule() : d(new QQmlTypeModulePrivate) { @@ -1218,14 +1354,16 @@ int QQmlTypeModule::maximumMinorVersion() const return d->maxMinorVersion; } -void QQmlTypeModulePrivate::add(QQmlType *type) +void QQmlTypeModulePrivate::add(QQmlTypePrivate *type) { - minMinorVersion = qMin(minMinorVersion, type->minorVersion()); - maxMinorVersion = qMax(maxMinorVersion, type->minorVersion()); + int minVersion = type->version_min; + minMinorVersion = qMin(minMinorVersion, minVersion); + maxMinorVersion = qMax(maxMinorVersion, minVersion); - QList<QQmlType *> &list = typeHash[type->elementName()]; + QList<QQmlTypePrivate *> &list = typeHash[type->elementName]; for (int ii = 0; ii < list.count(); ++ii) { - if (list.at(ii)->minorVersion() < type->minorVersion()) { + Q_ASSERT(list.at(ii)); + if (list.at(ii)->version_min < minVersion) { list.insert(ii, type); return; } @@ -1233,46 +1371,50 @@ void QQmlTypeModulePrivate::add(QQmlType *type) list.append(type); } -QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor) const +void QQmlTypeModulePrivate::remove(const QQmlTypePrivate *type) { - QMutexLocker lock(metaTypeDataLock()); - - QList<QQmlType *> *types = d->typeHash.value(name); - if (!types) return 0; + for (TypeHash::ConstIterator elementIt = typeHash.begin(); elementIt != typeHash.end();) { + QList<QQmlTypePrivate *> &list = typeHash[elementIt.key()]; - for (int ii = 0; ii < types->count(); ++ii) - if (types->at(ii)->minorVersion() <= minor) - return types->at(ii); + removeQQmlTypePrivate(list, type); - return 0; +#if 0 + if (list.isEmpty()) + elementIt = typeHash.erase(elementIt); + else + ++elementIt; +#else + ++elementIt; +#endif + } } -QQmlType *QQmlTypeModule::type(const QV4::String *name, int minor) const +QQmlType QQmlTypeModule::type(const QHashedStringRef &name, int minor) const { QMutexLocker lock(metaTypeDataLock()); - QList<QQmlType *> *types = d->typeHash.value(name); - if (!types) return 0; - - for (int ii = 0; ii < types->count(); ++ii) - if (types->at(ii)->minorVersion() <= minor) - return types->at(ii); + QList<QQmlTypePrivate *> *types = d->typeHash.value(name); + if (types) { + for (int ii = 0; ii < types->count(); ++ii) + if (types->at(ii)->version_min <= minor) + return QQmlType(types->at(ii)); + } - return 0; + return QQmlType(); } -QList<QQmlType*> QQmlTypeModule::singletonTypes(int minor) const +QQmlType QQmlTypeModule::type(const QV4::String *name, int minor) const { QMutexLocker lock(metaTypeDataLock()); - QList<QQmlType *> retn; - for (int ii = 0; ii < d->types.count(); ++ii) { - QQmlType *curr = d->types.at(ii); - if (curr->isSingleton() && curr->minorVersion() <= minor) - retn.append(curr); + QList<QQmlTypePrivate *> *types = d->typeHash.value(name); + if (types) { + for (int ii = 0; ii < types->count(); ++ii) + if (types->at(ii)->version_min <= minor) + return QQmlType(types->at(ii)); } - return retn; + return QQmlType(); } QQmlTypeModuleVersion::QQmlTypeModuleVersion() @@ -1309,16 +1451,18 @@ int QQmlTypeModuleVersion::minorVersion() const return m_minor; } -QQmlType *QQmlTypeModuleVersion::type(const QHashedStringRef &name) const +QQmlType QQmlTypeModuleVersion::type(const QHashedStringRef &name) const { - if (m_module) return m_module->type(name, m_minor); - else return 0; + if (!m_module) + return QQmlType(); + return m_module->type(name, m_minor); } -QQmlType *QQmlTypeModuleVersion::type(const QV4::String *name) const +QQmlType QQmlTypeModuleVersion::type(const QV4::String *name) const { - if (m_module) return m_module->type(name, m_minor); - else return 0; + if (!m_module) + return QQmlType(); + return m_module->type(name, m_minor); } void qmlClearTypeRegistrations() // Declared in qqml.h @@ -1327,9 +1471,6 @@ void qmlClearTypeRegistrations() // Declared in qqml.h QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - for (int i = 0; i < data->types.count(); ++i) - delete data->types.at(i); - for (QQmlMetaTypeData::TypeModules::const_iterator i = data->uriToModule.constBegin(), cend = data->uriToModule.constEnd(); i != cend; ++i) delete *i; @@ -1347,7 +1488,7 @@ void qmlClearTypeRegistrations() // Declared in qqml.h #endif } -int registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent) +static int registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent) { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); @@ -1357,7 +1498,7 @@ int registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent) return data->parentFunctions.count() - 1; } -int registerInterface(const QQmlPrivate::RegisterInterface &interface) +QQmlType registerInterface(const QQmlPrivate::RegisterInterface &interface) { if (interface.version > 0) qFatal("qmlRegisterType(): Cannot mix incompatible QML versions."); @@ -1365,16 +1506,15 @@ int registerInterface(const QQmlPrivate::RegisterInterface &interface) QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - int index = data->types.count(); + QQmlType type(data, interface); + QQmlTypePrivate *priv = type.priv(); + Q_ASSERT(priv); - QQmlType *type = new QQmlType(index, interface); - - data->types.append(type); - data->idToType.insert(type->typeId(), type); - data->idToType.insert(type->qListTypeId(), type); + data->idToType.insert(priv->typeId, priv); + data->idToType.insert(priv->listId, priv); // XXX No insertMulti, so no multi-version interfaces? - if (!type->elementName().isEmpty()) - data->nameToType.insert(type->elementName(), type); + if (!priv->elementName.isEmpty()) + data->nameToType.insert(priv->elementName, priv); if (data->interfaces.size() <= interface.typeId) data->interfaces.resize(interface.typeId + 16); @@ -1383,7 +1523,7 @@ int registerInterface(const QQmlPrivate::RegisterInterface &interface) data->interfaces.setBit(interface.typeId, true); data->lists.setBit(interface.listId, true); - return index; + return type; } QString registrationTypeString(QQmlType::RegistrationType typeType) @@ -1465,76 +1605,72 @@ QQmlTypeModule *getTypeModule(const QHashedString &uri, int majorVersion, QQmlMe } // NOTE: caller must hold a QMutexLocker on "data" -void addTypeToData(QQmlType* type, QQmlMetaTypeData *data) +void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data) { - if (!type->elementName().isEmpty()) - data->nameToType.insertMulti(type->elementName(), type); + Q_ASSERT(type); + + if (!type->elementName.isEmpty()) + data->nameToType.insertMulti(type->elementName, type); - if (type->baseMetaObject()) - data->metaObjectToType.insertMulti(type->baseMetaObject(), type); + if (type->baseMetaObject) + data->metaObjectToType.insertMulti(type->baseMetaObject, type); - if (type->typeId()) { - data->idToType.insert(type->typeId(), type); - if (data->objects.size() <= type->typeId()) - data->objects.resize(type->typeId() + 16); - data->objects.setBit(type->typeId(), true); + if (type->typeId) { + data->idToType.insert(type->typeId, type); + if (data->objects.size() <= type->typeId) + data->objects.resize(type->typeId + 16); + data->objects.setBit(type->typeId, true); } - if (type->qListTypeId()) { - if (data->lists.size() <= type->qListTypeId()) - data->lists.resize(type->qListTypeId() + 16); - data->lists.setBit(type->qListTypeId(), true); - data->idToType.insert(type->qListTypeId(), type); + if (type->listId) { + if (data->lists.size() <= type->listId) + data->lists.resize(type->listId + 16); + data->lists.setBit(type->listId, true); + data->idToType.insert(type->listId, type); } - if (!type->module().isEmpty()) { - const QHashedString &mod = type->module(); + if (!type->module.isEmpty()) { + const QHashedString &mod = type->module; - QQmlTypeModule *module = getTypeModule(mod, type->majorVersion(), data); + QQmlTypeModule *module = getTypeModule(mod, type->version_maj, data); Q_ASSERT(module); module->d->add(type); } } -int registerType(const QQmlPrivate::RegisterType &type) +QQmlType registerType(const QQmlPrivate::RegisterType &type) { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); QString elementName = QString::fromUtf8(type.elementName); if (!checkRegistration(QQmlType::CppType, data, type.uri, elementName, type.versionMajor)) - return -1; - - int index = data->types.count(); + return QQmlType(); - QQmlType *dtype = new QQmlType(index, elementName, type); + QQmlType dtype(data, elementName, type); - data->types.append(dtype); - addTypeToData(dtype, data); + addTypeToData(dtype.priv(), data); if (!type.typeId) - data->idToType.insert(dtype->typeId(), dtype); + data->idToType.insert(dtype.typeId(), dtype.priv()); - return index; + return dtype; } -int registerSingletonType(const QQmlPrivate::RegisterSingletonType &type) +QQmlType registerSingletonType(const QQmlPrivate::RegisterSingletonType &type) { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); QString typeName = QString::fromUtf8(type.typeName); if (!checkRegistration(QQmlType::SingletonType, data, type.uri, typeName, type.versionMajor)) - return -1; + return QQmlType(); - int index = data->types.count(); + QQmlType dtype(data, typeName, type); - QQmlType *dtype = new QQmlType(index, typeName, type); + addTypeToData(dtype.priv(), data); - data->types.append(dtype); - addTypeToData(dtype, data); - - return index; + return dtype; } -int registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &type) +QQmlType QQmlMetaType::registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &type) { // Assumes URL is absolute and valid. Checking of user input should happen before the URL enters type. QMutexLocker lock(metaTypeDataLock()); @@ -1544,22 +1680,19 @@ int registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingleton if (*(type.uri) == '\0') fileImport = true; if (!checkRegistration(QQmlType::CompositeSingletonType, data, fileImport ? 0 : type.uri, typeName)) - return -1; + return QQmlType(); - int index = data->types.count(); + QQmlType dtype(data, typeName, type); - QQmlType *dtype = new QQmlType(index, typeName, type); - - data->types.append(dtype); - addTypeToData(dtype, data); + addTypeToData(dtype.priv(), data); QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType); - files->insertMulti(type.url, dtype); + files->insertMulti(type.url, dtype.priv()); - return index; + return dtype; } -int registerCompositeType(const QQmlPrivate::RegisterCompositeType &type) +QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterCompositeType &type) { // Assumes URL is absolute and valid. Checking of user input should happen before the URL enters type. QMutexLocker lock(metaTypeDataLock()); @@ -1569,18 +1702,56 @@ int registerCompositeType(const QQmlPrivate::RegisterCompositeType &type) if (*(type.uri) == '\0') fileImport = true; if (!checkRegistration(QQmlType::CompositeType, data, fileImport?0:type.uri, typeName, type.versionMajor)) - return -1; - - int index = data->types.count(); + return QQmlType(); - QQmlType *dtype = new QQmlType(index, typeName, type); - data->types.append(dtype); - addTypeToData(dtype, data); + QQmlType dtype(data, typeName, type); + addTypeToData(dtype.priv(), data); QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType); - files->insertMulti(type.url, dtype); + files->insertMulti(type.url, dtype.priv()); + + return dtype; +} + +void QQmlMetaType::registerInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit) +{ + QByteArray name = compilationUnit->rootPropertyCache()->className(); + + QByteArray ptr = name + '*'; + QByteArray lst = "QQmlListProperty<" + name + '>'; + + int ptr_type = QMetaType::registerNormalizedType(ptr, + QtMetaTypePrivate::QMetaTypeFunctionHelper<QObject*>::Destruct, + QtMetaTypePrivate::QMetaTypeFunctionHelper<QObject*>::Construct, + sizeof(QObject*), + static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QObject*>::Flags), + 0); + int lst_type = QMetaType::registerNormalizedType(lst, + QtMetaTypePrivate::QMetaTypeFunctionHelper<QQmlListProperty<QObject> >::Destruct, + QtMetaTypePrivate::QMetaTypeFunctionHelper<QQmlListProperty<QObject> >::Construct, + sizeof(QQmlListProperty<QObject>), + static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QQmlListProperty<QObject> >::Flags), + static_cast<QMetaObject*>(0)); - return index; + compilationUnit->metaTypeId = ptr_type; + compilationUnit->listMetaTypeId = lst_type; + + QMutexLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *d = metaTypeData(); + d->qmlLists.insert(lst_type, ptr_type); +} + +void QQmlMetaType::unregisterInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit) +{ + int ptr_type = compilationUnit->metaTypeId; + int lst_type = compilationUnit->listMetaTypeId; + + QMutexLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *d = metaTypeData(); + d->qmlLists.remove(lst_type); + + QMetaType::unregisterType(ptr_type); + QMetaType::unregisterType(lst_type); } int registerQmlUnitCacheHook(const QQmlPrivate::RegisterQmlUnitCacheHook &hookRegistration) @@ -1599,22 +1770,30 @@ the future without adding exported symbols. */ int QQmlPrivate::qmlregister(RegistrationType type, void *data) { - if (type == TypeRegistration) { - return registerType(*reinterpret_cast<RegisterType *>(data)); - } else if (type == InterfaceRegistration) { - return registerInterface(*reinterpret_cast<RegisterInterface *>(data)); - } else if (type == AutoParentRegistration) { + if (type == AutoParentRegistration) return registerAutoParentFunction(*reinterpret_cast<RegisterAutoParent *>(data)); - } else if (type == SingletonRegistration) { - return registerSingletonType(*reinterpret_cast<RegisterSingletonType *>(data)); - } else if (type == CompositeRegistration) { - return registerCompositeType(*reinterpret_cast<RegisterCompositeType *>(data)); - } else if (type == CompositeSingletonRegistration) { - return registerCompositeSingletonType(*reinterpret_cast<RegisterCompositeSingletonType *>(data)); - } else if (type == QmlUnitCacheHookRegistration) { + else if (type == QmlUnitCacheHookRegistration) return registerQmlUnitCacheHook(*reinterpret_cast<RegisterQmlUnitCacheHook *>(data)); - } - return -1; + + QQmlType dtype; + if (type == TypeRegistration) + dtype = registerType(*reinterpret_cast<RegisterType *>(data)); + else if (type == InterfaceRegistration) + dtype = registerInterface(*reinterpret_cast<RegisterInterface *>(data)); + else if (type == SingletonRegistration) + dtype = registerSingletonType(*reinterpret_cast<RegisterSingletonType *>(data)); + else if (type == CompositeRegistration) + dtype = QQmlMetaType::registerCompositeType(*reinterpret_cast<RegisterCompositeType *>(data)); + else if (type == CompositeSingletonRegistration) + dtype = QQmlMetaType::registerCompositeSingletonType(*reinterpret_cast<RegisterCompositeSingletonType *>(data)); + else + return -1; + + QMutexLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *typeData = metaTypeData(); + typeData->undeletableTypes.insert(dtype); + + return dtype.index(); } //From qqml.h @@ -1654,8 +1833,8 @@ bool QQmlMetaType::namespaceContainsRegistrations(const QString &uri, int majorV // Has any type previously been installed to this namespace? QHashedString nameSpace(uri); - for (const QQmlType *type : data->types) - if (type->module() == nameSpace && type->majorVersion() == majorVersion) + for (const QQmlType &type : data->types) + if (type.module() == nameSpace && type.majorVersion() == majorVersion) return true; return false; @@ -1787,9 +1966,12 @@ int QQmlMetaType::listType(int id) { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - QQmlType *type = data->idToType.value(id); - if (type && type->qListTypeId() == id) - return type->typeId(); + QHash<int, int>::ConstIterator iter = data->qmlLists.constFind(id); + if (iter != data->qmlLists.cend()) + return *iter; + QQmlTypePrivate *type = data->idToType.value(id); + if (type && type->listId == id) + return type->typeId; else return 0; } @@ -1799,9 +1981,9 @@ int QQmlMetaType::attachedPropertiesFuncId(QQmlEnginePrivate *engine, const QMet QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - QQmlType *type = data->metaObjectToType.value(mo); - if (type && type->attachedPropertiesFunction(engine)) - return type->attachedPropertiesId(engine); + QQmlType type(data->metaObjectToType.value(mo)); + if (type.attachedPropertiesFunction(engine)) + return type.attachedPropertiesId(engine); else return -1; } @@ -1812,7 +1994,7 @@ QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(QQmlEnginePr return 0; QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - return data->types.at(id)->attachedPropertiesFunction(engine); + return data->types.at(id).attachedPropertiesFunction(engine); } QMetaProperty QQmlMetaType::defaultProperty(const QMetaObject *metaObject) @@ -1876,7 +2058,9 @@ QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType) QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - if (userType < data->objects.size() && data->objects.testBit(userType)) + if (data->qmlLists.contains(userType)) + return List; + else if (userType < data->objects.size() && data->objects.testBit(userType)) return Object; else if (userType < data->lists.size() && data->lists.testBit(userType)) return List; @@ -1895,10 +2079,10 @@ const char *QQmlMetaType::interfaceIId(int userType) { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - QQmlType *type = data->idToType.value(userType); + QQmlType type(data->idToType.value(userType)); lock.unlock(); - if (type && type->isInterface() && type->typeId() == userType) - return type->interfaceIId(); + if (type.isInterface() && type.typeId() == userType) + return type.interfaceIId(); else return 0; } @@ -1907,6 +2091,8 @@ bool QQmlMetaType::isList(int userType) { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); + if (data->qmlLists.contains(userType)) + return true; return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType); } @@ -1951,11 +2137,11 @@ QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type) Returns the type (if any) of URI-qualified named \a qualifiedName and version specified by \a version_major and \a version_minor. */ -QQmlType *QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, int version_minor) +QQmlType QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, int version_minor) { int slash = qualifiedName.indexOf(QLatin1Char('/')); if (slash <= 0) - return 0; + return QQmlType(); QHashedStringRef module(qualifiedName.constData(), slash); QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.length() - slash - 1); @@ -1967,7 +2153,7 @@ QQmlType *QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, Returns the type (if any) of \a name in \a module and version specified by \a version_major and \a version_minor. */ -QQmlType *QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor) +QQmlType QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor) { Q_ASSERT(version_major >= 0 && version_minor >= 0); QMutexLocker lock(metaTypeDataLock()); @@ -1975,25 +2161,26 @@ QQmlType *QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStrin QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.constFind(name); while (it != data->nameToType.cend() && it.key() == name) { + QQmlType t(*it); // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty - if (version_major < 0 || module.isEmpty() || (*it)->availableInVersion(module, version_major,version_minor)) - return (*it); + if (version_major < 0 || module.isEmpty() || t.availableInVersion(module, version_major,version_minor)) + return t; ++it; } - return 0; + return QQmlType(); } /*! Returns the type (if any) that corresponds to the \a metaObject. Returns null if no type is registered. */ -QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject) +QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject) { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - return data->metaObjectToType.value(metaObject); + return QQmlType(data->metaObjectToType.value(metaObject)); } /*! @@ -2001,7 +2188,7 @@ QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject) by \a version_major and \a version_minor in module specified by \a uri. Returns null if no type is registered. */ -QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor) +QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor) { Q_ASSERT(version_major >= 0 && version_minor >= 0); QMutexLocker lock(metaTypeDataLock()); @@ -2009,29 +2196,29 @@ QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStri QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.constFind(metaObject); while (it != data->metaObjectToType.cend() && it.key() == metaObject) { - QQmlType *t = *it; - if (version_major < 0 || module.isEmpty() || t->availableInVersion(module, version_major,version_minor)) + QQmlType t(*it); + if (version_major < 0 || module.isEmpty() || t.availableInVersion(module, version_major,version_minor)) return t; ++it; } - return 0; + return QQmlType(); } /*! Returns the type (if any) that corresponds to the QVariant::Type \a userType. Returns null if no type is registered. */ -QQmlType *QQmlMetaType::qmlType(int userType) +QQmlType QQmlMetaType::qmlType(int userType) { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - QQmlType *type = data->idToType.value(userType); - if (type && type->typeId() == userType) - return type; + QQmlTypePrivate *type = data->idToType.value(userType); + if (type && type->typeId == userType) + return QQmlType(type); else - return 0; + return QQmlType(); } /*! @@ -2040,34 +2227,209 @@ QQmlType *QQmlMetaType::qmlType(int userType) Returns null if no such type is registered. */ -QQmlType *QQmlMetaType::qmlType(const QUrl &url, bool includeNonFileImports /* = false */) +QQmlType QQmlMetaType::qmlType(const QUrl &url, bool includeNonFileImports /* = false */) { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - QQmlType *type = data->urlToType.value(url); - if (!type && includeNonFileImports) - type = data->urlToNonFileImportType.value(url); + QQmlType type(data->urlToType.value(url)); + if (!type.isValid() && includeNonFileImports) + type = QQmlType(data->urlToNonFileImportType.value(url)); - if (type && type->sourceUrl() == url) + if (type.sourceUrl() == url) return type; else + return QQmlType(); +} + +QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QMetaObject *metaObject) +{ + if (QQmlPropertyCache *rv = propertyCaches.value(metaObject)) + return rv; + + if (!metaObject->superClass()) { + QQmlPropertyCache *rv = new QQmlPropertyCache(metaObject); + propertyCaches.insert(metaObject, rv); + return rv; + } + QQmlPropertyCache *super = propertyCache(metaObject->superClass()); + QQmlPropertyCache *rv = super->copyAndAppend(metaObject); + propertyCaches.insert(metaObject, rv); + return rv; +} + +QQmlPropertyCache *QQmlMetaType::propertyCache(const QMetaObject *metaObject) +{ + QMutexLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + return data->propertyCache(metaObject); +} + +QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int minorVersion) +{ + Q_ASSERT(type.isValid()); + + if (QQmlPropertyCache *pc = type.key()->propertyCacheForMinorVersion(minorVersion)) + return pc; + + QVector<QQmlType> types; + + int maxMinorVersion = 0; + + const QMetaObject *metaObject = type.metaObject(); + + while (metaObject) { + QQmlType t = QQmlMetaType::qmlType(metaObject, type.module(), type.majorVersion(), minorVersion); + if (t.isValid()) { + maxMinorVersion = qMax(maxMinorVersion, t.minorVersion()); + types << t; + } else { + types << QQmlType(); + } + + metaObject = metaObject->superClass(); + } + + if (QQmlPropertyCache *pc = type.key()->propertyCacheForMinorVersion(maxMinorVersion)) { + const_cast<QQmlTypePrivate*>(type.key())->setPropertyCacheForMinorVersion(minorVersion, pc); + return pc; + } + + QQmlPropertyCache *raw = propertyCache(type.metaObject()); + + bool hasCopied = false; + + for (int ii = 0; ii < types.count(); ++ii) { + QQmlType currentType = types.at(ii); + if (!currentType.isValid()) + continue; + + int rev = currentType.metaObjectRevision(); + int moIndex = types.count() - 1 - ii; + + if (raw->allowedRevisionCache[moIndex] != rev) { + if (!hasCopied) { + raw = raw->copy(); + hasCopied = true; + } + raw->allowedRevisionCache[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) { + + QQmlPropertyData *d = *iter; + if (raw->isAllowedInRevision(d)) + continue; // Not excluded - no problems + + // check that a regular "name" overload isn't happening + 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 + + const_cast<QQmlTypePrivate*>(type.key())->setPropertyCacheForMinorVersion(minorVersion, raw); + + if (hasCopied) + raw->release(); + + if (minorVersion != maxMinorVersion) + const_cast<QQmlTypePrivate*>(type.key())->setPropertyCacheForMinorVersion(maxMinorVersion, raw); + + return raw; } -/*! - Returns the type (if any) with the given \a index in the global type store. - This is for use when you just got the index back from a qmlRegister function. - Returns null if the index is out of bounds. -*/ -QQmlType *QQmlMetaType::qmlTypeFromIndex(int idx) +QQmlPropertyCache *QQmlMetaType::propertyCache(const QQmlType &type, int minorVersion) { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); + return data->propertyCache(type, minorVersion); +} + +void QQmlMetaType::freeUnusedTypesAndCaches() +{ + QMutexLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + + { + bool deletedAtLeastOneType; + do { + deletedAtLeastOneType = false; + QList<QQmlType>::Iterator it = data->types.begin(); + while (it != data->types.end()) { + const QQmlTypePrivate *d = (*it).priv(); + if (d && d->refCount == 1) { + deletedAtLeastOneType = true; + + removeQQmlTypePrivate(data->idToType, d); + removeQQmlTypePrivate(data->nameToType, d); + removeQQmlTypePrivate(data->urlToType, d); + removeQQmlTypePrivate(data->urlToNonFileImportType, d); + removeQQmlTypePrivate(data->metaObjectToType, d); + + for (QQmlMetaTypeData::TypeModules::Iterator module = data->uriToModule.begin(); module != data->uriToModule.end(); ++module) { + QQmlTypeModulePrivate *modulePrivate = (*module)->priv(); + modulePrivate->remove(d); + } + + *it = QQmlType(); + } else { + ++it; + } + } + } while (deletedAtLeastOneType); + } - if (idx < 0 || idx >= data->types.count()) - return 0; - return data->types.at(idx); + { + bool deletedAtLeastOneCache; + do { + deletedAtLeastOneCache = false; + QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator it = data->propertyCaches.begin(); + while (it != data->propertyCaches.end()) { + + if ((*it)->count() == 1) { + QQmlPropertyCache *pc = Q_NULLPTR; + qSwap(pc, *it); + it = data->propertyCaches.erase(it); + pc->release(); + deletedAtLeastOneCache = true; + } else { + ++it; + } + } + } while (deletedAtLeastOneCache); + } } /*! @@ -2082,7 +2444,8 @@ QList<QString> QQmlMetaType::qmlTypeNames() names.reserve(data->nameToType.count()); QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.cbegin(); while (it != data->nameToType.cend()) { - names += (*it)->qmlTypeName(); + QQmlType t(*it); + names += t.qmlTypeName(); ++it; } @@ -2092,18 +2455,22 @@ QList<QString> QQmlMetaType::qmlTypeNames() /*! Returns the list of registered QML types. */ -QList<QQmlType*> QQmlMetaType::qmlTypes() +QList<QQmlType> QQmlMetaType::qmlTypes() { QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + const QQmlMetaTypeData *data = metaTypeData(); + + QList<QQmlType> types; + for (QQmlTypePrivate *t : data->nameToType) + types.append(QQmlType(t)); - return data->nameToType.values(); + return types; } /*! Returns the list of all registered types. */ -QList<QQmlType*> QQmlMetaType::qmlAllTypes() +QList<QQmlType> QQmlMetaType::qmlAllTypes() { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); @@ -2114,14 +2481,15 @@ QList<QQmlType*> QQmlMetaType::qmlAllTypes() /*! Returns the list of registered QML singleton types. */ -QList<QQmlType*> QQmlMetaType::qmlSingletonTypes() +QList<QQmlType> QQmlMetaType::qmlSingletonTypes() { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - QList<QQmlType*> retn; - for (const auto type : qAsConst(data->nameToType)) { - if (type->isSingleton()) + QList<QQmlType> retn; + for (const auto t : qAsConst(data->nameToType)) { + QQmlType type(t); + if (type.isSingleton()) retn.append(type); } return retn; @@ -2149,9 +2517,9 @@ QString QQmlMetaType::prettyTypeName(const QObject *object) if (!object) return typeName; - const QQmlType *type = QQmlMetaType::qmlType(object->metaObject()); - if (type) { - typeName = type->qmlTypeName(); + QQmlType type = QQmlMetaType::qmlType(object->metaObject()); + if (type.isValid()) { + typeName = type.qmlTypeName(); const int lastSlash = typeName.lastIndexOf(QLatin1Char('/')); if (lastSlash != -1) typeName = typeName.mid(lastSlash + 1); @@ -2167,8 +2535,8 @@ QString QQmlMetaType::prettyTypeName(const QObject *object) if (marker != -1) { typeName = typeName.leftRef(marker) + QLatin1Char('*'); type = QQmlMetaType::qmlType(QMetaType::type(typeName.toLatin1())); - if (type) { - QString qmlTypeName = type->qmlTypeName(); + if (type.isValid()) { + QString qmlTypeName = type.qmlTypeName(); const int lastSlash = qmlTypeName.lastIndexOf(QLatin1Char('/')); if (lastSlash != -1) qmlTypeName = qmlTypeName.mid(lastSlash + 1); diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index 4dd28bbd36..8eb91f321a 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -70,24 +70,36 @@ class QQmlTypeModule; class QHashedString; class QHashedStringRef; class QMutex; +class QQmlPropertyCache; +class QQmlCompiledData; namespace QV4 { struct String; } class Q_QML_PRIVATE_EXPORT QQmlMetaType { public: + static QQmlType registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &type); + static QQmlType registerCompositeType(const QQmlPrivate::RegisterCompositeType &type); + + static void registerInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit); + static void unregisterInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit); + static QList<QString> qmlTypeNames(); - static QList<QQmlType*> qmlTypes(); - static QList<QQmlType*> qmlSingletonTypes(); - static QList<QQmlType*> qmlAllTypes(); - - static QQmlType *qmlType(const QString &qualifiedName, int, int); - static QQmlType *qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int, int); - static QQmlType *qmlType(const QMetaObject *); - static QQmlType *qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor); - static QQmlType *qmlType(int); - static QQmlType *qmlType(const QUrl &url, bool includeNonFileImports = false); - static QQmlType *qmlTypeFromIndex(int); + static QList<QQmlType> qmlTypes(); + static QList<QQmlType> qmlSingletonTypes(); + static QList<QQmlType> qmlAllTypes(); + + static QQmlType qmlType(const QString &qualifiedName, int, int); + static QQmlType qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int, int); + static QQmlType qmlType(const QMetaObject *); + static QQmlType qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor); + static QQmlType qmlType(int); + static QQmlType qmlType(const QUrl &url, bool includeNonFileImports = false); + + static QQmlPropertyCache *propertyCache(const QMetaObject *metaObject); + static QQmlPropertyCache *propertyCache(const QQmlType &type, int minorVersion); + + static void freeUnusedTypesAndCaches(); static QMetaProperty defaultProperty(const QMetaObject *); static QMetaProperty defaultProperty(QObject *); @@ -135,14 +147,28 @@ public: struct QQmlMetaTypeData; class QHashedCStringRef; +class QQmlPropertyCache; class Q_QML_PRIVATE_EXPORT QQmlType { public: + QQmlType(); + QQmlType(const QQmlType &other); + QQmlType &operator =(const QQmlType &other); + explicit QQmlType(QQmlTypePrivate *priv); + ~QQmlType(); + + bool operator ==(const QQmlType &other) const { + return d == other.d; + } + + bool isValid() const { return d != 0; } + const QQmlTypePrivate *key() const { return d; } + QByteArray typeName() const; - const QString &qmlTypeName() const; - const QString &elementName() const; + QString qmlTypeName() const; + QString elementName() const; - const QHashedString &module() const; + QHashedString module() const; int majorVersion() const; int minorVersion() const; @@ -224,18 +250,9 @@ public: int scopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &, const QByteArray &, bool *ok) const; int scopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &, const QStringRef &, bool *ok) const; -private: - QQmlType *superType() const; - QQmlType *resolveCompositeBaseType(QQmlEnginePrivate *engine) const; - int resolveCompositeEnumValue(QQmlEnginePrivate *engine, const QString &name, bool *ok) const; - int resolveCompositeScopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *, bool *ok) const; - int resolveCompositeScopedEnumIndex(QQmlEnginePrivate *engine, const QString &name, bool *ok) const; - int resolveCompositeScopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *, bool *ok) const; - int resolveCompositeScopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &name, bool *ok) const; - int resolveCompositeScopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &scopedName, const QByteArray &name, bool *ok) const; - int resolveCompositeScopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &scopedName, const QStringRef &name, bool *ok) const; - friend class QQmlTypePrivate; - friend struct QQmlMetaTypeData; + QQmlTypePrivate *priv() const { return d; } + static void refHandle(QQmlTypePrivate *priv); + static void derefHandle(QQmlTypePrivate *priv); enum RegistrationType { CppType = 0, @@ -244,25 +261,39 @@ private: CompositeType = 3, CompositeSingletonType = 4 }; + +private: + QQmlType superType() const; + QQmlType resolveCompositeBaseType(QQmlEnginePrivate *engine) const; + int resolveCompositeEnumValue(QQmlEnginePrivate *engine, const QString &name, bool *ok) const; + QQmlPropertyCache *compositePropertyCache(QQmlEnginePrivate *engine) const; + friend class QQmlTypePrivate; + friend QString registrationTypeString(RegistrationType); friend bool checkRegistration(RegistrationType, QQmlMetaTypeData *, const char *, const QString &, int); - friend int registerType(const QQmlPrivate::RegisterType &); - friend int registerSingletonType(const QQmlPrivate::RegisterSingletonType &); - friend int registerInterface(const QQmlPrivate::RegisterInterface &); - friend int registerCompositeType(const QQmlPrivate::RegisterCompositeType &); - friend int registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &); + friend QQmlType registerType(const QQmlPrivate::RegisterType &); + friend QQmlType registerSingletonType(const QQmlPrivate::RegisterSingletonType &); + friend QQmlType registerInterface(const QQmlPrivate::RegisterInterface &); friend int registerQmlUnitCacheHook(const QQmlPrivate::RegisterQmlUnitCacheHook &); + friend uint qHash(const QQmlType &t, uint seed); friend Q_QML_EXPORT void qmlClearTypeRegistrations(); - QQmlType(int, const QQmlPrivate::RegisterInterface &); - QQmlType(int, const QString &, const QQmlPrivate::RegisterSingletonType &); - QQmlType(int, const QString &, const QQmlPrivate::RegisterType &); - QQmlType(int, const QString &, const QQmlPrivate::RegisterCompositeType &); - QQmlType(int, const QString &, const QQmlPrivate::RegisterCompositeSingletonType &); - ~QQmlType(); + friend class QQmlMetaType; + + QQmlType(QQmlMetaTypeData *data, const QQmlPrivate::RegisterInterface &); + QQmlType(QQmlMetaTypeData *data, const QString &, const QQmlPrivate::RegisterSingletonType &); + QQmlType(QQmlMetaTypeData *data, const QString &, const QQmlPrivate::RegisterType &); + QQmlType(QQmlMetaTypeData *data, const QString &, const QQmlPrivate::RegisterCompositeType &); + QQmlType(QQmlMetaTypeData *data, const QString &, const QQmlPrivate::RegisterCompositeSingletonType &); QQmlTypePrivate *d; }; +Q_DECLARE_TYPEINFO(QQmlMetaType, Q_MOVABLE_TYPE); + + +inline uint qHash(const QQmlType &t, uint seed = 0) { return qHash(reinterpret_cast<quintptr>(t.d), seed); } + + class QQmlTypeModulePrivate; class QQmlTypeModule { @@ -273,15 +304,14 @@ public: int minimumMinorVersion() const; int maximumMinorVersion() const; - QQmlType *type(const QHashedStringRef &, int) const; - QQmlType *type(const QV4::String *, int) const; - - QList<QQmlType*> singletonTypes(int) const; + QQmlType type(const QHashedStringRef &, int) const; + QQmlType type(const QV4::String *, int) const; + QQmlTypeModulePrivate *priv() { return d; } private: //Used by register functions and creates the QQmlTypeModule for them friend QQmlTypeModule *getTypeModule(const QHashedString &uri, int majorVersion, QQmlMetaTypeData *data); - friend void addTypeToData(QQmlType* type, QQmlMetaTypeData *data); + friend void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data); friend struct QQmlMetaTypeData; friend Q_QML_EXPORT void qmlClearTypeRegistrations(); friend class QQmlTypeModulePrivate; @@ -302,8 +332,8 @@ public: QQmlTypeModule *module() const; int minorVersion() const; - QQmlType *type(const QHashedStringRef &) const; - QQmlType *type(const QV4::String *) const; + QQmlType type(const QHashedStringRef &) const; + QQmlType type(const QV4::String *) const; private: QQmlTypeModule *m_module; diff --git a/src/qml/qml/qqmlnotifier.cpp b/src/qml/qml/qqmlnotifier.cpp index 538ca822ee..938e2b77e2 100644 --- a/src/qml/qml/qqmlnotifier.cpp +++ b/src/qml/qml/qqmlnotifier.cpp @@ -117,7 +117,7 @@ void QQmlNotifier::emitNotify(QQmlNotifierEndpoint *endpoint, void **a) \a sourceSignal MUST be in the signal index range (see QObjectPrivate::signalIndex()). This is different from QMetaMethod::methodIndex(). */ -void QQmlNotifierEndpoint::connect(QObject *source, int sourceSignal, QQmlEngine *engine) +void QQmlNotifierEndpoint::connect(QObject *source, int sourceSignal, QQmlEngine *engine, bool doNotify) { disconnect(); @@ -142,8 +142,11 @@ void QQmlNotifierEndpoint::connect(QObject *source, int sourceSignal, QQmlEngine QQmlPropertyPrivate::flushSignal(source, sourceSignal); QQmlData *ddata = QQmlData::get(source, true); ddata->addNotify(sourceSignal, this); - QObjectPrivate * const priv = QObjectPrivate::get(source); - priv->connectNotify(QMetaObjectPrivate::signal(source->metaObject(), sourceSignal)); + if (doNotify) { + needsConnectNotify = doNotify; + QObjectPrivate * const priv = QObjectPrivate::get(source); + priv->connectNotify(QMetaObjectPrivate::signal(source->metaObject(), sourceSignal)); + } } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlnotifier_p.h b/src/qml/qml/qqmlnotifier_p.h index dad79e0e55..a99b13f155 100644 --- a/src/qml/qml/qqmlnotifier_p.h +++ b/src/qml/qml/qqmlnotifier_p.h @@ -100,7 +100,7 @@ public: inline bool isConnected(QObject *source, int sourceSignal) const; inline bool isConnected(QQmlNotifier *) const; - void connect(QObject *source, int sourceSignal, QQmlEngine *engine); + void connect(QObject *source, int sourceSignal, QQmlEngine *engine, bool doNotify = true); inline void connect(QQmlNotifier *); inline void disconnect(); @@ -109,6 +109,9 @@ public: inline int signalIndex() const { return sourceSignal; } + inline QObject *senderAsObject() const; + inline QQmlNotifier *senderAsNotifier() const; + private: friend class QQmlData; friend class QQmlNotifier; @@ -117,13 +120,12 @@ private: // endpoint is connected to. While the endpoint is notifying, the // senderPtr points to another qintptr that contains this value. qintptr senderPtr; - inline QObject *senderAsObject() const; - inline QQmlNotifier *senderAsNotifier() const; Callback callback:4; + int needsConnectNotify:1; // The index is in the range returned by QObjectPrivate::signalIndex(). // This is different from QMetaMethod::methodIndex(). - signed int sourceSignal:28; + signed int sourceSignal:27; }; QQmlNotifier::QQmlNotifier() @@ -155,7 +157,7 @@ void QQmlNotifier::notify() } QQmlNotifierEndpoint::QQmlNotifierEndpoint(Callback callback) -: next(0), prev(0), senderPtr(0), callback(callback), sourceSignal(-1) +: next(0), prev(0), senderPtr(0), callback(callback), needsConnectNotify(false), sourceSignal(-1) { } @@ -205,7 +207,8 @@ void QQmlNotifierEndpoint::disconnect() if (sourceSignal != -1) { QObject * const obj = senderAsObject(); QObjectPrivate * const priv = QObjectPrivate::get(obj); - priv->disconnectNotify(QMetaObjectPrivate::signal(obj->metaObject(), sourceSignal)); + if (needsConnectNotify) + priv->disconnectNotify(QMetaObjectPrivate::signal(obj->metaObject(), sourceSignal)); } if (isNotifying()) *((qintptr *)(senderPtr & ~0x1)) = 0; diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 2cbcfbbfb6..cc9cc889d0 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -613,11 +613,11 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const } } -static QQmlType *qmlTypeForObject(QObject *object) +static QQmlType qmlTypeForObject(QObject *object) { - QQmlType *type = 0; + QQmlType type; const QMetaObject *mo = object->metaObject(); - while (mo && !type) { + while (mo && !type.isValid()) { type = QQmlMetaType::qmlType(mo); mo = mo->superClass(); } @@ -654,7 +654,7 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings) } else if (binding) { QQmlValueTypeProxyBinding *proxy = static_cast<QQmlValueTypeProxyBinding *>(binding); - if (qmlTypeForObject(_bindingTarget)) { + if (qmlTypeForObject(_bindingTarget).isValid()) { quint32 bindingSkipList = 0; QQmlPropertyData *defaultProperty = _compiledObject->indexOfDefaultPropertyOrAlias != -1 ? _propertyCache->parent()->defaultProperty() : _propertyCache->defaultProperty(); @@ -712,15 +712,15 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con Q_ASSERT(stringAt(qmlUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex).isEmpty()); QV4::CompiledData::ResolvedTypeReference *tr = resolvedTypes.value(binding->propertyNameIndex); Q_ASSERT(tr); - QQmlType *attachedType = tr->type; - if (!attachedType) { + QQmlType attachedType = tr->type; + if (!attachedType.isValid()) { QQmlTypeNameCache::Result res = context->imports->query(stringAt(binding->propertyNameIndex)); if (res.isValid()) attachedType = res.type; else return false; } - const int id = attachedType->attachedPropertiesId(QQmlEnginePrivate::get(engine)); + const int id = attachedType.attachedPropertiesId(QQmlEnginePrivate::get(engine)); QObject *qmlObject = qmlAttachedPropertiesObjectById(id, _qobject); if (!populateInstance(binding->value.objectIndex, qmlObject, qmlObject, /*value type property*/0)) return false; @@ -801,17 +801,13 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con && !_valueTypeProperty) QQmlPropertyPrivate::removeBinding(_bindingTarget, QQmlPropertyIndex(property->coreIndex())); - if (binding->type == QV4::CompiledData::Binding::Type_Script) { - QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]; - - QV4::Scope scope(v4); - QV4::Scoped<QV4::QmlContext> qmlContext(scope, currentQmlContext()); - + if (binding->type == QV4::CompiledData::Binding::Type_Script || binding->containsTranslations()) { if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) { + QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]; int signalIndex = _propertyCache->methodIndexToSignalIndex(property->coreIndex()); QQmlBoundSignal *bs = new QQmlBoundSignal(_bindingTarget, signalIndex, _scopeObject, engine); QQmlBoundSignalExpression *expr = new QQmlBoundSignalExpression(_bindingTarget, signalIndex, - context, _scopeObject, runtimeFunction, qmlContext); + context, _scopeObject, runtimeFunction, currentQmlContext()); bs->takeExpression(expr); } else { @@ -827,7 +823,12 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con prop = _valueTypeProperty; subprop = property; } - qmlBinding = QQmlBinding::create(prop, runtimeFunction, _scopeObject, context, qmlContext); + if (binding->containsTranslations()) { + qmlBinding = QQmlBinding::createTranslationBinding(compilationUnit, binding, _scopeObject, context); + } else { + QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]; + qmlBinding = QQmlBinding::create(prop, runtimeFunction, _scopeObject, context, currentQmlContext()); + } qmlBinding->setTarget(_bindingTarget, *prop, subprop); sharedState->allCreatedBindings.push(QQmlAbstractBinding::Ptr(qmlBinding)); @@ -850,10 +851,10 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con if (binding->type == QV4::CompiledData::Binding::Type_Object) { if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) { // ### determine value source and interceptor casts ahead of time. - QQmlType *type = qmlTypeForObject(createdSubObject); - Q_ASSERT(type); + QQmlType type = qmlTypeForObject(createdSubObject); + Q_ASSERT(type.isValid()); - int valueSourceCast = type->propertyValueSourceCast(); + int valueSourceCast = type.propertyValueSourceCast(); if (valueSourceCast != -1) { QQmlPropertyValueSource *vs = reinterpret_cast<QQmlPropertyValueSource *>(reinterpret_cast<char *>(createdSubObject) + valueSourceCast); QObject *target = createdSubObject->parent(); @@ -865,7 +866,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con vs->setTarget(prop); return true; } - int valueInterceptorCast = type->propertyValueInterceptorCast(); + int valueInterceptorCast = type.propertyValueInterceptorCast(); if (valueInterceptorCast != -1) { QQmlPropertyValueInterceptor *vi = reinterpret_cast<QQmlPropertyValueInterceptor *>(reinterpret_cast<char *>(createdSubObject) + valueInterceptorCast); QObject *target = createdSubObject->parent(); @@ -996,7 +997,7 @@ void QQmlObjectCreator::setupFunctions() QV4::ScopedValue function(scope); QV4::ScopedContext qmlContext(scope, currentQmlContext()); - const QV4::CompiledData::LEUInt32 *functionIdx = _compiledObject->functionOffsetTable(); + const quint32_le *functionIdx = _compiledObject->functionOffsetTable(); for (quint32 i = 0; i < _compiledObject->nFunctions; ++i, ++functionIdx) { QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[*functionIdx]; const QString name = runtimeFunction->name()->toQString(); @@ -1026,12 +1027,12 @@ void QQmlObjectCreator::registerObjectWithContextById(const QV4::CompiledData::O context->setIdProperty(object->id, instance); } -QV4::Heap::QmlContext *QQmlObjectCreator::currentQmlContext() +QV4::QmlContext *QQmlObjectCreator::currentQmlContext() { if (!_qmlContext->isManaged()) _qmlContext->setM(QV4::QmlContext::create(v4->rootContext(), context, _scopeObject)); - return _qmlContext->d(); + return _qmlContext; } QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isContextObject) @@ -1060,13 +1061,13 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo QV4::CompiledData::ResolvedTypeReference *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex); Q_ASSERT(typeRef); installPropertyCache = !typeRef->isFullyDynamicType; - QQmlType *type = typeRef->type; - if (type) { + QQmlType type = typeRef->type; + if (type.isValid()) { Q_QML_OC_PROFILE(sharedState->profiler, profiler.update( - compilationUnit, obj, type->qmlTypeName(), context->url())); + compilationUnit, obj, type.qmlTypeName(), context->url())); void *ddataMemory = 0; - type->create(&instance, &ddataMemory, sizeof(QQmlData)); + type.create(&instance, &ddataMemory, sizeof(QQmlData)); if (!instance) { recordError(obj->location, tr("Unable to create object of type %1").arg(stringAt(obj->inheritedTypeNameIndex))); return 0; @@ -1080,11 +1081,11 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo p->declarativeData = ddata; } - const int parserStatusCast = type->parserStatusCast(); + const int parserStatusCast = type.parserStatusCast(); if (parserStatusCast != -1) parserStatus = reinterpret_cast<QQmlParserStatus*>(reinterpret_cast<char *>(instance) + parserStatusCast); - customParser = type->customParser(); + customParser = type.customParser(); if (sharedState->rootContext && sharedState->rootContext->isRootObjectInCreation) { QQmlData *ddata = QQmlData::get(instance, /*create*/true); @@ -1325,7 +1326,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * if (propertyCaches->needsVMEMetaObject(_compiledObjectIndex)) { Q_ASSERT(!cache.isNull()); // install on _object - vmeMetaObject = new QQmlVMEMetaObject(_qobject, cache, compilationUnit, _compiledObjectIndex); + vmeMetaObject = new QQmlVMEMetaObject(v4, _qobject, cache, compilationUnit, _compiledObjectIndex); if (_ddata->propertyCache) _ddata->propertyCache->release(); _ddata->propertyCache = cache; diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index 982324be3c..45c14f0963 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -122,7 +122,7 @@ private: void registerObjectWithContextById(const QV4::CompiledData::Object *object, QObject *instance) const; - QV4::Heap::QmlContext *currentQmlContext(); + QV4::QmlContext *currentQmlContext(); enum Phase { Startup, diff --git a/src/qml/qml/qqmlopenmetaobject.cpp b/src/qml/qml/qqmlopenmetaobject.cpp index 49f02476a2..fc85030b3d 100644 --- a/src/qml/qml/qqmlopenmetaobject.cpp +++ b/src/qml/qml/qqmlopenmetaobject.cpp @@ -376,7 +376,7 @@ void QQmlOpenMetaObject::setCached(bool c) QQmlData *qmldata = QQmlData::get(d->object, true); if (d->cacheProperties) { if (!d->type->d->cache) - d->type->d->cache = new QQmlPropertyCache(QV8Engine::getV4(d->type->d->engine), this); + d->type->d->cache = new QQmlPropertyCache(this); qmldata->propertyCache = d->type->d->cache; d->type->d->cache->addref(); } else { diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 9b5f7b0a06..21bbcadb1c 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -253,24 +253,24 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name) if (typeNameCache) { QQmlTypeNameCache::Result r = typeNameCache->query(pathName); if (r.isValid()) { - if (r.type) { + if (r.type.isValid()) { QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine); - QQmlAttachedPropertiesFunc func = r.type->attachedPropertiesFunction(enginePrivate); + QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate); if (!func) return; // Not an attachable type - currentObject = qmlAttachedPropertiesObjectById(r.type->attachedPropertiesId(enginePrivate), currentObject); + currentObject = qmlAttachedPropertiesObjectById(r.type.attachedPropertiesId(enginePrivate), currentObject); if (!currentObject) return; // Something is broken with the attachable type } else if (r.importNamespace) { if ((ii + 1) == path.count()) return; // No type following the namespace ++ii; r = typeNameCache->query(path.at(ii), r.importNamespace); - if (!r.type) return; // Invalid type in namespace + if (!r.type.isValid()) return; // Invalid type in namespace QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine); - QQmlAttachedPropertiesFunc func = r.type->attachedPropertiesFunction(enginePrivate); + QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate); if (!func) return; // Not an attachable type - currentObject = qmlAttachedPropertiesObjectById(r.type->attachedPropertiesId(enginePrivate), currentObject); + currentObject = qmlAttachedPropertiesObjectById(r.type.attachedPropertiesId(enginePrivate), currentObject); if (!currentObject) return; // Something is broken with the attachable type } else if (r.scriptIndex != -1) { @@ -1275,10 +1275,10 @@ bool QQmlPropertyPrivate::write(QObject *object, if (enginePriv) { listType = enginePriv->rawMetaObjectForType(enginePriv->listType(property.propType())); } else { - QQmlType *type = QQmlMetaType::qmlType(QQmlMetaType::listType(property.propType())); - if (!type) + QQmlType type = QQmlMetaType::qmlType(QQmlMetaType::listType(property.propType())); + if (!type.isValid()) return false; - listType = type->baseMetaObject(); + listType = type.baseMetaObject(); } if (listType.isNull()) return false; @@ -1393,8 +1393,9 @@ QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engi return metaType.metaObject(); if (engine) return engine->rawMetaObjectForType(userType); - if (QQmlType *type = QQmlMetaType::qmlType(userType)) - return QQmlMetaObject(type->baseMetaObject()); + QQmlType type = QQmlMetaType::qmlType(userType); + if (type.isValid()) + return QQmlMetaObject(type.baseMetaObject()); return QQmlMetaObject(); } diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index d18159841c..7178dffa8b 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -99,7 +99,7 @@ static QQmlPropertyData::Flags fastFlagsForProperty(const QMetaProperty &p) // Flags that do depend on the property's QMetaProperty::userType() and thus are slow to // load -static void flagsForPropertyType(int propType, QQmlEngine *engine, QQmlPropertyData::Flags &flags) +static void flagsForPropertyType(int propType, QQmlPropertyData::Flags &flags) { Q_ASSERT(propType != -1); @@ -116,9 +116,7 @@ static void flagsForPropertyType(int propType, QQmlEngine *engine, QQmlPropertyD } else if (propType == qMetaTypeId<QQmlV4Handle>()) { flags.type = QQmlPropertyData::Flags::V4HandleType; } else { - QQmlMetaType::TypeCategory cat = - engine ? QQmlEnginePrivate::get(engine)->typeCategory(propType) - : QQmlMetaType::typeCategory(propType); + QQmlMetaType::TypeCategory cat = QQmlMetaType::typeCategory(propType); if (cat == QQmlMetaType::Object || QMetaType::typeFlags(propType) & QMetaType::PointerToQObject) flags.type = QQmlPropertyData::Flags::QObjectDerivedType; @@ -136,10 +134,10 @@ static int metaObjectSignalCount(const QMetaObject *metaObject) } QQmlPropertyData::Flags -QQmlPropertyData::flagsForProperty(const QMetaProperty &p, QQmlEngine *engine) +QQmlPropertyData::flagsForProperty(const QMetaProperty &p) { auto flags = fastFlagsForProperty(p); - flagsForPropertyType(p.userType(), engine, flags); + flagsForPropertyType(p.userType(), flags); return flags; } @@ -166,13 +164,13 @@ void QQmlPropertyData::lazyLoad(const QMetaProperty &p) } } -void QQmlPropertyData::load(const QMetaProperty &p, QQmlEngine *engine) +void QQmlPropertyData::load(const QMetaProperty &p) { setPropType(p.userType()); setCoreIndex(p.propertyIndex()); setNotifyIndex(QMetaObjectPrivate::signalIndex(p.notifySignal())); setFlags(fastFlagsForProperty(p)); - flagsForPropertyType(propType(), engine, _flags); + flagsForPropertyType(propType(), _flags); Q_ASSERT(p.revision() <= Q_INT16_MAX); setRevision(p.revision()); } @@ -244,19 +242,18 @@ void QQmlPropertyData::lazyLoad(const QMetaMethod &m) /*! Creates a new empty QQmlPropertyCache. */ -QQmlPropertyCache::QQmlPropertyCache(QV4::ExecutionEngine *e) - : engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), +QQmlPropertyCache::QQmlPropertyCache() + : _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false), _metaObject(0), argumentsCache(0), _jsFactoryMethodIndex(-1) { - Q_ASSERT(engine); } /*! Creates a new QQmlPropertyCache of \a metaObject. */ -QQmlPropertyCache::QQmlPropertyCache(QV4::ExecutionEngine *e, const QMetaObject *metaObject) - : QQmlPropertyCache(e) +QQmlPropertyCache::QQmlPropertyCache(const QMetaObject *metaObject) + : QQmlPropertyCache() { Q_ASSERT(metaObject); @@ -265,8 +262,6 @@ QQmlPropertyCache::QQmlPropertyCache(QV4::ExecutionEngine *e, const QMetaObject QQmlPropertyCache::~QQmlPropertyCache() { - clear(); - QQmlPropertyCacheMethodArguments *args = argumentsCache; while (args) { QQmlPropertyCacheMethodArguments *next = args->next; @@ -284,24 +279,11 @@ QQmlPropertyCache::~QQmlPropertyCache() if (_ownMetaObject) free(const_cast<QMetaObject *>(_metaObject)); _metaObject = 0; _parent = 0; - engine = 0; -} - -void QQmlPropertyCache::destroy() -{ - delete this; -} - -// This is inherited from QQmlCleanup, so it should only clear the things -// that are tied to the specific QQmlEngine. -void QQmlPropertyCache::clear() -{ - engine = 0; } QQmlPropertyCache *QQmlPropertyCache::copy(int reserve) { - QQmlPropertyCache *cache = new QQmlPropertyCache(engine); + QQmlPropertyCache *cache = new QQmlPropertyCache(); cache->_parent = this; cache->_parent->addref(); cache->propertyIndexCacheStart = propertyIndexCache.count() + propertyIndexCacheStart; @@ -321,12 +303,13 @@ QQmlPropertyCache *QQmlPropertyCache::copy() } QQmlPropertyCache *QQmlPropertyCache::copyAndReserve(int propertyCount, int methodCount, - int signalCount) + int signalCount, int enumCount) { QQmlPropertyCache *rv = copy(propertyCount + methodCount + signalCount); rv->propertyIndexCache.reserve(propertyCount); rv->methodIndexCache.reserve(methodCount); rv->signalHandlerIndexCache.reserve(signalCount); + rv->enumCache.reserve(enumCount); rv->_metaObject = 0; return rv; @@ -421,6 +404,14 @@ void QQmlPropertyCache::appendMethod(const QString &name, QQmlPropertyData::Flag setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0)); } +void QQmlPropertyCache::appendEnum(const QString &name, const QVector<QQmlEnumValue> &values) +{ + QQmlEnumData data; + data.name = name; + data.values = values; + enumCache.append(data); +} + // Returns this property cache's metaObject, creating it if necessary. const QMetaObject *QQmlPropertyCache::createMetaObject() { @@ -711,7 +702,7 @@ void QQmlPropertyCache::resolve(QQmlPropertyData *data) const data->setPropType(registerResult == -1 ? QMetaType::UnknownType : registerResult); } } - flagsForPropertyType(data->propType(), engine->qmlEngine(), data->_flags); + flagsForPropertyType(data->propType(), data->_flags); } } @@ -782,7 +773,11 @@ void QQmlPropertyCache::invalidate(const QMetaObject *metaObject) QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, QObject *object, QQmlContextData *context) const { QQmlData *data = (object ? QQmlData::get(object) : 0); - const QQmlVMEMetaObject *vmemo = (data && data->hasVMEMetaObject ? static_cast<const QQmlVMEMetaObject *>(object->metaObject()) : 0); + const QQmlVMEMetaObject *vmemo = 0; + if (data && data->hasVMEMetaObject) { + QObjectPrivate *op = QObjectPrivate::get(object); + vmemo = static_cast<const QQmlVMEMetaObject *>(op->metaObject); + } return findProperty(it, vmemo, context); } @@ -826,9 +821,9 @@ QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, } if (vmemo) { - const int methodCount = vmemo->methodCount(); - const int signalCount = vmemo->signalCount(); - const int propertyCount = vmemo->propertyCount(); + const int methodCount = vmemo->cache->methodCount(); + const int signalCount = vmemo->cache->signalCount(); + const int propertyCount = vmemo->cache->propertyCount(); // Ensure that the property we resolve to is accessible from this meta-object do { @@ -1245,6 +1240,16 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) method.setReturnType(returnType); } + for (int ii = 0; ii < enumCache.count(); ++ii) { + const QQmlEnumData &enumData = enumCache.at(ii); + QMetaEnumBuilder enumeration = builder.addEnumerator(enumData.name.toUtf8()); + enumeration.setIsScoped(true); + for (int jj = 0; jj < enumData.values.count(); ++jj) { + const QQmlEnumValue &value = enumData.values.at(jj); + enumeration.addKey(value.namedValue.toUtf8(), value.value); + } + } + if (!_defaultPropertyName.isEmpty()) { QQmlPropertyData *dp = property(_defaultPropertyName, 0, 0); if (dp && dp->coreIndex() >= propertyIndexCacheStart) { diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index 64be1cb206..6cdb82bd46 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -288,8 +288,8 @@ public: inline bool operator==(const QQmlPropertyRawData &); - static Flags flagsForProperty(const QMetaProperty &, QQmlEngine *engine = 0); - void load(const QMetaProperty &, QQmlEngine *engine = 0); + static Flags flagsForProperty(const QMetaProperty &); + void load(const QMetaProperty &); void load(const QMetaMethod &); QString name(QObject *) const; QString name(const QMetaObject *) const; @@ -349,12 +349,26 @@ private: bool notFullyResolved() const { return _flags.notFullyResolved; } }; +struct QQmlEnumValue +{ + QQmlEnumValue() : value(-1) {} + QQmlEnumValue(const QString &n, int v) : namedValue(n), value(v) {} + QString namedValue; + int value; +}; + +struct QQmlEnumData +{ + QString name; + QVector<QQmlEnumValue> values; +}; + class QQmlPropertyCacheMethodArguments; -class Q_QML_PRIVATE_EXPORT QQmlPropertyCache : public QQmlRefCount, public QQmlCleanup +class Q_QML_PRIVATE_EXPORT QQmlPropertyCache : public QQmlRefCount { public: - QQmlPropertyCache(QV4::ExecutionEngine *); - QQmlPropertyCache(QV4::ExecutionEngine *, const QMetaObject *); + QQmlPropertyCache(); + QQmlPropertyCache(const QMetaObject *); virtual ~QQmlPropertyCache(); void update(const QMetaObject *); @@ -374,13 +388,14 @@ public: QQmlPropertyRawData::Flags signalFlags = QQmlPropertyData::Flags()); QQmlPropertyCache *copyAndReserve(int propertyCount, - int methodCount, int signalCount); + int methodCount, int signalCount, int enumCount); void appendProperty(const QString &, QQmlPropertyRawData::Flags flags, int coreIndex, int propType, int notifyIndex); void appendSignal(const QString &, QQmlPropertyRawData::Flags, int coreIndex, const int *types = 0, const QList<QByteArray> &names = QList<QByteArray>()); void appendMethod(const QString &, QQmlPropertyData::Flags flags, int coreIndex, const QList<QByteArray> &names = QList<QByteArray>()); + void appendEnum(const QString &, const QVector<QQmlEnumValue> &); const QMetaObject *metaObject() const; const QMetaObject *createMetaObject(); @@ -395,6 +410,7 @@ public: QQmlPropertyData *property(int) const; QQmlPropertyData *method(int) const; QQmlPropertyData *signal(int index) const; + QQmlEnumData *qmlEnum(int) const; int methodIndexToSignalIndex(int) const; QString defaultPropertyName() const; @@ -434,6 +450,7 @@ public: inline int methodOffset() const; inline int signalCount() const; inline int signalOffset() const; + inline int qmlEnumCount() const; static bool isDynamicMetaObject(const QMetaObject *); @@ -445,11 +462,6 @@ public: static bool addToHash(QCryptographicHash &hash, const QMetaObject &mo); QByteArray checksum(bool *ok); - -protected: - void destroy() override; - void clear() override; - private: friend class QQmlEnginePrivate; friend class QQmlCompiler; @@ -457,6 +469,7 @@ private: template <typename T> friend class QQmlPropertyCacheAliasCreator; friend class QQmlComponentAndAliasResolver; friend class QQmlMetaObject; + friend struct QQmlMetaTypeData; inline QQmlPropertyCache *copy(int reserve); @@ -493,9 +506,6 @@ private: _hasPropertyOverrides |= isOverride; } -public: - QV4::ExecutionEngine *engine; - private: QQmlPropertyCache *_parent; int propertyIndexCacheStart; @@ -507,6 +517,7 @@ private: IndexCache signalHandlerIndexCache; StringCache stringCache; AllowedRevisionCache allowedRevisionCache; + QVector<QQmlEnumData> enumCache; bool _hasPropertyOverrides : 1; bool _ownMetaObject : 1; @@ -519,6 +530,8 @@ private: QByteArray _checksum; }; +typedef QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCachePtr; + // QQmlMetaObject serves as a wrapper around either QMetaObject or QQmlPropertyCache. // This is necessary as we delay creation of QMetaObject for synthesized QObjects, but // we don't want to needlessly generate QQmlPropertyCaches every time we encounter a @@ -747,6 +760,14 @@ inline QQmlPropertyData *QQmlPropertyCache::signal(int index) const return ensureResolved(rv); } +inline QQmlEnumData *QQmlPropertyCache::qmlEnum(int index) const +{ + if (index < 0 || index >= enumCache.count()) + return 0; + + return const_cast<QQmlEnumData *>(&enumCache.at(index)); +} + inline int QQmlPropertyCache::methodIndexToSignalIndex(int index) const { if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count())) @@ -817,6 +838,11 @@ int QQmlPropertyCache::signalOffset() const return signalHandlerIndexCacheStart; } +int QQmlPropertyCache::qmlEnumCount() const +{ + return enumCache.count(); +} + bool QQmlPropertyCache::callJSFactoryMethod(QObject *object, void **args) const { if (_jsFactoryMethodIndex != -1) { diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index de19fe3cd7..6601429be4 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -1779,23 +1779,21 @@ QString QQmlTypeLoader::absoluteFilePath(const QString &path) #endif int lastSlash = path.lastIndexOf(QLatin1Char('/')); - QStringRef dirPath(&path, 0, lastSlash); + QString dirPath(path.left(lastSlash)); - StringSet **fileSet = m_importDirCache.value(QHashedStringRef(dirPath.constData(), dirPath.length())); - if (!fileSet) { - QHashedString dirPathString(dirPath.toString()); - bool exists = QDir(dirPathString).exists(); - QStringHash<bool> *files = exists ? new QStringHash<bool> : 0; - m_importDirCache.insert(dirPathString, files); - fileSet = m_importDirCache.value(dirPathString); + if (!m_importDirCache.contains(dirPath)) { + bool exists = QDir(dirPath).exists(); + QCache<QString, bool> *entry = exists ? new QCache<QString, bool> : 0; + m_importDirCache.insert(dirPath, entry); } - if (!(*fileSet)) + QCache<QString, bool> *fileSet = m_importDirCache.object(dirPath); + if (!fileSet) return QString(); QString absoluteFilePath; - QHashedStringRef fileName(path.constData()+lastSlash+1, path.length()-lastSlash-1); + QString fileName(path.mid(lastSlash+1, path.length()-lastSlash-1)); - bool *value = (*fileSet)->value(fileName); + bool *value = fileSet->object(fileName); if (value) { if (*value) absoluteFilePath = path; @@ -1809,7 +1807,7 @@ QString QQmlTypeLoader::absoluteFilePath(const QString &path) #else exists = QFile::exists(path); #endif - (*fileSet)->insert(fileName.toString(), exists); + fileSet->insert(fileName, new bool(exists)); if (exists) absoluteFilePath = path; } @@ -1844,18 +1842,16 @@ bool QQmlTypeLoader::directoryExists(const QString &path) int length = path.length(); if (path.endsWith(QLatin1Char('/'))) --length; - QStringRef dirPath(&path, 0, length); + QString dirPath(path.left(length)); - StringSet **fileSet = m_importDirCache.value(QHashedStringRef(dirPath.constData(), dirPath.length())); - if (!fileSet) { - QHashedString dirPathString(dirPath.toString()); - bool exists = QDir(dirPathString).exists(); - QStringHash<bool> *files = exists ? new QStringHash<bool> : 0; - m_importDirCache.insert(dirPathString, files); - fileSet = m_importDirCache.value(dirPathString); + if (!m_importDirCache.contains(dirPath)) { + bool exists = QDir(dirPath).exists(); + QCache<QString, bool> *files = exists ? new QCache<QString, bool> : 0; + m_importDirCache.insert(dirPath, files); } - return (*fileSet); + QCache<QString, bool> *fileSet = m_importDirCache.object(dirPath); + return fileSet != 0; } @@ -1939,7 +1935,7 @@ void QQmlTypeLoader::clearCache() (*iter)->release(); for (QmldirCache::Iterator iter = m_qmldirCache.begin(), end = m_qmldirCache.end(); iter != end; ++iter) (*iter)->release(); - qDeleteAll(m_importDirCache); + qDeleteAll(m_importQmlDirCache); m_typeCache.clear(); @@ -1948,6 +1944,7 @@ void QQmlTypeLoader::clearCache() m_qmldirCache.clear(); m_importDirCache.clear(); m_importQmlDirCache.clear(); + QQmlMetaType::freeUnusedTypesAndCaches(); } void QQmlTypeLoader::updateTypeCacheTrimThreshold() @@ -1989,6 +1986,8 @@ void QQmlTypeLoader::trimCache() updateTypeCacheTrimThreshold(); + QQmlMetaType::freeUnusedTypesAndCaches(); + // TODO: release any scripts which are no longer referenced by any types } @@ -2014,7 +2013,7 @@ QString QQmlTypeData::TypeReference::qualifiedName() const if (!prefix.isEmpty()) { result = prefix + QLatin1Char('.'); } - result.append(type->qmlTypeName()); + result.append(type.qmlTypeName()); return result; } @@ -2169,8 +2168,8 @@ static bool addTypeReferenceChecksumsToHash(const QList<QQmlTypeData::TypeRefere if (typeRef.typeData) { const auto unit = typeRef.typeData->compilationUnit(); hash->addData(unit->data->md5Checksum, sizeof(unit->data->md5Checksum)); - } else if (typeRef.type) { - const auto propertyCache = QQmlEnginePrivate::get(engine)->cache(typeRef.type->metaObject()); + } else if (typeRef.type.isValid()) { + const auto propertyCache = QQmlEnginePrivate::get(engine)->cache(typeRef.type.metaObject()); bool ok = false; hash->addData(propertyCache->checksum(&ok)); if (!ok) @@ -2234,7 +2233,7 @@ void QQmlTypeData::done() const TypeReference &type = m_compositeSingletons.at(ii); Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError()); if (type.typeData && type.typeData->isError()) { - QString typeName = type.type->qmlTypeName(); + QString typeName = type.type.qmlTypeName(); QList<QQmlError> errors = type.typeData->errors(); QQmlError error; @@ -2301,24 +2300,24 @@ void QQmlTypeData::done() } { - QQmlType *type = QQmlMetaType::qmlType(finalUrl(), true); + QQmlType type = QQmlMetaType::qmlType(finalUrl(), true); if (m_compiledData && m_compiledData->data->flags & QV4::CompiledData::Unit::IsSingleton) { - if (!type) { + if (!type.isValid()) { QQmlError error; error.setDescription(QQmlTypeLoader::tr("No matching type found, pragma Singleton files cannot be used by QQmlComponent.")); setError(error); return; - } else if (!type->isCompositeSingleton()) { + } else if (!type.isCompositeSingleton()) { QQmlError error; - error.setDescription(QQmlTypeLoader::tr("pragma Singleton used with a non composite singleton type %1").arg(type->qmlTypeName())); + error.setDescription(QQmlTypeLoader::tr("pragma Singleton used with a non composite singleton type %1").arg(type.qmlTypeName())); setError(error); return; } } else { // If the type is CompositeSingleton but there was no pragma Singleton in the // QML file, lets report an error. - if (type && type->isCompositeSingleton()) { - QString typeName = type->qmlTypeName(); + if (type.isValid() && type.isCompositeSingleton()) { + QString typeName = type.qmlTypeName(); setError(QQmlTypeLoader::tr("qmldir defines type as singleton, but no pragma Singleton found in type %1.").arg(typeName)); return; } @@ -2610,8 +2609,8 @@ void QQmlTypeData::resolveTypes() if (!resolveType(typeName, majorVersion, minorVersion, ref)) return; - if (ref.type->isCompositeSingleton()) { - ref.typeData = typeLoader()->getType(ref.type->sourceUrl()); + if (ref.type.isCompositeSingleton()) { + ref.typeData = typeLoader()->getType(ref.type.sourceUrl()); addDependency(ref.typeData); ref.prefix = csRef.prefix; @@ -2638,8 +2637,8 @@ void QQmlTypeData::resolveTypes() if (!resolveType(name, majorVersion, minorVersion, ref, unresolvedRef->location.line, unresolvedRef->location.column, reportErrors) && reportErrors) return; - if (ref.type && ref.type->isComposite()) { - ref.typeData = typeLoader()->getType(ref.type->sourceUrl()); + if (ref.type.isComposite()) { + ref.typeData = typeLoader()->getType(ref.type.sourceUrl()); addDependency(ref.typeData); } ref.majorVersion = majorVersion; @@ -2652,6 +2651,10 @@ void QQmlTypeData::resolveTypes() m_resolvedTypes.insert(unresolvedRef.key(), ref); } + + // ### this allows enums to work without explicit import or instantiation of the type + if (!m_implicitImportLoaded) + loadImplicitImport(); } QQmlCompileError QQmlTypeData::buildTypeResolutionCaches( @@ -2666,7 +2669,7 @@ QQmlCompileError QQmlTypeData::buildTypeResolutionCaches( // Add any Composite Singletons that were used to the import cache for (const QQmlTypeData::TypeReference &singleton: m_compositeSingletons) - (*typeNameCache)->add(singleton.type->qmlTypeName(), singleton.type->sourceUrl(), singleton.prefix); + (*typeNameCache)->add(singleton.type.qmlTypeName(), singleton.type.sourceUrl(), singleton.prefix); m_importCache.populateCache(*typeNameCache); @@ -2674,24 +2677,24 @@ QQmlCompileError QQmlTypeData::buildTypeResolutionCaches( for (auto resolvedType = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); resolvedType != end; ++resolvedType) { QScopedPointer<QV4::CompiledData::ResolvedTypeReference> ref(new QV4::CompiledData::ResolvedTypeReference); - QQmlType *qmlType = resolvedType->type; + QQmlType qmlType = resolvedType->type; if (resolvedType->typeData) { - if (resolvedType->needsCreation && qmlType->isCompositeSingleton()) { - return QQmlCompileError(resolvedType->location, tr("Composite Singleton Type %1 is not creatable.").arg(qmlType->qmlTypeName())); + if (resolvedType->needsCreation && qmlType.isCompositeSingleton()) { + return QQmlCompileError(resolvedType->location, tr("Composite Singleton Type %1 is not creatable.").arg(qmlType.qmlTypeName())); } ref->compilationUnit = resolvedType->typeData->compilationUnit(); - } else if (qmlType) { + } else if (qmlType.isValid()) { ref->type = qmlType; - Q_ASSERT(ref->type); + Q_ASSERT(ref->type.isValid()); - if (resolvedType->needsCreation && !ref->type->isCreatable()) { - QString reason = ref->type->noCreationReason(); + if (resolvedType->needsCreation && !ref->type.isCreatable()) { + QString reason = ref->type.noCreationReason(); if (reason.isEmpty()) reason = tr("Element is not creatable."); return QQmlCompileError(resolvedType->location, reason); } - if (ref->type->containsRevisionedAttributes()) { + if (ref->type.containsRevisionedAttributes()) { ref->typePropertyCache = engine->cache(ref->type, resolvedType->minorVersion); } diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index f367fa6f58..05923f77e8 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -55,6 +55,7 @@ #include <QtCore/qobject.h> #include <QtCore/qatomic.h> #include <QtCore/qfileinfo.h> +#include <QtCore/qcache.h> #if QT_CONFIG(qml_network) #include <QtNetwork/qnetworkreply.h> #endif @@ -362,8 +363,7 @@ private: typedef QHash<QUrl, QQmlTypeData *> TypeCache; typedef QHash<QUrl, QQmlScriptBlob *> ScriptCache; typedef QHash<QUrl, QQmlQmldirData *> QmldirCache; - typedef QStringHash<bool> StringSet; - typedef QStringHash<StringSet*> ImportDirCache; + typedef QCache<QString, QCache<QString, bool> > ImportDirCache; typedef QStringHash<QQmlTypeLoaderQmldirContent *> ImportQmlDirCache; QQmlEngine *m_engine; @@ -393,10 +393,10 @@ class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlTypeLoader::Blob public: struct TypeReference { - TypeReference() : type(0), majorVersion(0), minorVersion(0), typeData(0), needsCreation(true) {} + TypeReference() : majorVersion(0), minorVersion(0), typeData(0), needsCreation(true) {} QV4::CompiledData::Location location; - QQmlType *type; + QQmlType type; int majorVersion; int minorVersion; QQmlTypeData *typeData; diff --git a/src/qml/qml/qqmltypenamecache.cpp b/src/qml/qml/qqmltypenamecache.cpp index c8e2b92c29..136614d332 100644 --- a/src/qml/qml/qqmltypenamecache.cpp +++ b/src/qml/qml/qqmltypenamecache.cpp @@ -55,7 +55,7 @@ QQmlTypeNameCache::~QQmlTypeNameCache() void QQmlTypeNameCache::add(const QHashedString &name, const QUrl &url, const QHashedString &nameSpace) { if (nameSpace.length() != 0) { - Import *i = m_namedImports.value(nameSpace); + QQmlImportRef *i = m_namedImports.value(nameSpace); Q_ASSERT(i != 0); i->compositeSingletons.insert(name, url); return; @@ -69,12 +69,12 @@ void QQmlTypeNameCache::add(const QHashedString &name, const QUrl &url, const QH void QQmlTypeNameCache::add(const QHashedString &name, int importedScriptIndex, const QHashedString &nameSpace) { - Import import; + QQmlImportRef import; import.scriptIndex = importedScriptIndex; import.m_qualifier = name; if (nameSpace.length() != 0) { - Import *i = m_namedImports.value(nameSpace); + QQmlImportRef *i = m_namedImports.value(nameSpace); Q_ASSERT(i != 0); m_namespacedImports[i].insert(name, import); return; @@ -100,7 +100,7 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name) // Look up anonymous types from the imports of this document QQmlImportNamespace *typeNamespace = 0; QList<QQmlError> errors; - QQmlType *t = 0; + QQmlType t; bool typeFound = m_imports.resolveType(name, &t, 0, 0, &typeNamespace, &errors); if (typeFound) { return Result(t); @@ -112,25 +112,23 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name) } QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name, - const void *importNamespace) const + const QQmlImportRef *importNamespace) const { - Q_ASSERT(importNamespace); - const Import *i = static_cast<const Import *>(importNamespace); - Q_ASSERT(i->scriptIndex == -1); + Q_ASSERT(importNamespace && importNamespace->scriptIndex == -1); - Result result = typeSearch(i->modules, name); + Result result = typeSearch(importNamespace->modules, name); if (!result.isValid()) - result = query(i->compositeSingletons, name); + result = query(importNamespace->compositeSingletons, name); if (!result.isValid()) { // Look up types from the imports of this document // ### it would be nice if QQmlImports allowed us to resolve a namespace // first, and then types on it. - QString qualifiedTypeName = i->m_qualifier + QLatin1Char('.') + name.toString(); + QString qualifiedTypeName = importNamespace->m_qualifier + QLatin1Char('.') + name.toString(); QQmlImportNamespace *typeNamespace = 0; QList<QQmlError> errors; - QQmlType *t = 0; + QQmlType t; bool typeFound = m_imports.resolveType(qualifiedTypeName, &t, 0, 0, &typeNamespace, &errors); if (typeFound) { return Result(t); @@ -140,7 +138,7 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name, return result; } -QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name) const +QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, QQmlImport::RecursionRestriction recursionRestriction) const { Result result = query(m_namedImports, name); @@ -155,8 +153,8 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name) cons QString typeName = name->toQStringNoThrow(); QQmlImportNamespace *typeNamespace = 0; QList<QQmlError> errors; - QQmlType *t = 0; - bool typeFound = m_imports.resolveType(typeName, &t, 0, 0, &typeNamespace, &errors); + QQmlType t; + bool typeFound = m_imports.resolveType(typeName, &t, 0, 0, &typeNamespace, &errors, recursionRestriction); if (typeFound) { return Result(t); } @@ -166,32 +164,30 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name) cons return result; } -QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, const void *importNamespace) const +QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, const QQmlImportRef *importNamespace) const { - Q_ASSERT(importNamespace); - const Import *i = static_cast<const Import *>(importNamespace); - Q_ASSERT(i->scriptIndex == -1); + Q_ASSERT(importNamespace && importNamespace->scriptIndex == -1); - QMap<const Import *, QStringHash<Import> >::const_iterator it = m_namespacedImports.constFind(i); + QMap<const QQmlImportRef *, QStringHash<QQmlImportRef> >::const_iterator it = m_namespacedImports.constFind(importNamespace); if (it != m_namespacedImports.constEnd()) { Result r = query(*it, name); if (r.isValid()) return r; } - Result r = typeSearch(i->modules, name); + Result r = typeSearch(importNamespace->modules, name); if (!r.isValid()) - r = query(i->compositeSingletons, name); + r = query(importNamespace->compositeSingletons, name); if (!r.isValid()) { // Look up types from the imports of this document // ### it would be nice if QQmlImports allowed us to resolve a namespace // first, and then types on it. - QString qualifiedTypeName = i->m_qualifier + QLatin1Char('.') + name->toQStringNoThrow(); + QString qualifiedTypeName = importNamespace->m_qualifier + QLatin1Char('.') + name->toQStringNoThrow(); QQmlImportNamespace *typeNamespace = 0; QList<QQmlError> errors; - QQmlType *t = 0; + QQmlType t; bool typeFound = m_imports.resolveType(qualifiedTypeName, &t, 0, 0, &typeNamespace, &errors); if (typeFound) { return Result(t); diff --git a/src/qml/qml/qqmltypenamecache_p.h b/src/qml/qml/qqmltypenamecache_p.h index 7cdcbe91b6..6e5cd0fb54 100644 --- a/src/qml/qml/qqmltypenamecache_p.h +++ b/src/qml/qml/qqmltypenamecache_p.h @@ -62,6 +62,23 @@ QT_BEGIN_NAMESPACE +struct QQmlImportRef { + inline QQmlImportRef() + : scriptIndex(-1) + {} + // Imported module + QVector<QQmlTypeModuleVersion> modules; + + // Or, imported script + int scriptIndex; + + // Or, imported compositeSingletons + QStringHash<QUrl> compositeSingletons; + + // The qualifier of this import + QString m_qualifier; +}; + class QQmlType; class QQmlEngine; class QQmlTypeNameCache : public QQmlRefCount @@ -77,50 +94,35 @@ public: struct Result { inline Result(); - inline Result(const void *importNamespace); - inline Result(QQmlType *type); + inline Result(const QQmlImportRef *importNamespace); + inline Result(const QQmlType &type); inline Result(int scriptIndex); inline Result(const Result &); inline bool isValid() const; - QQmlType *type; - const void *importNamespace; + QQmlType type; + const QQmlImportRef *importNamespace; int scriptIndex; }; Result query(const QHashedStringRef &) const; - Result query(const QHashedStringRef &, const void *importNamespace) const; - Result query(const QV4::String *) const; - Result query(const QV4::String *, const void *importNamespace) const; + Result query(const QHashedStringRef &, const QQmlImportRef *importNamespace) const; + Result query(const QV4::String *, QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion) const; + Result query(const QV4::String *, const QQmlImportRef *importNamespace) const; private: friend class QQmlImports; - struct Import { - inline Import(); - // Imported module - QVector<QQmlTypeModuleVersion> modules; - - // Or, imported script - int scriptIndex; - - // Or, imported compositeSingletons - QStringHash<QUrl> compositeSingletons; - - // The qualifier of this import - QString m_qualifier; - }; - template<typename Key> - Result query(const QStringHash<Import> &imports, Key key) const + Result query(const QStringHash<QQmlImportRef> &imports, Key key) const { - Import *i = imports.value(key); + QQmlImportRef *i = imports.value(key); if (i) { Q_ASSERT(!i->m_qualifier.isEmpty()); if (i->scriptIndex != -1) { return Result(i->scriptIndex); } else { - return Result(static_cast<const void *>(i)); + return Result(i); } } @@ -132,9 +134,8 @@ private: { QUrl *url = urls.value(key); if (url) { - QQmlType *type = QQmlMetaType::qmlType(*url); - if (type) - return Result(type); + QQmlType type = QQmlMetaType::qmlType(*url); + return Result(type); } return Result(); @@ -145,37 +146,38 @@ private: { QVector<QQmlTypeModuleVersion>::const_iterator end = modules.constEnd(); for (QVector<QQmlTypeModuleVersion>::const_iterator it = modules.constBegin(); it != end; ++it) { - if (QQmlType *type = it->type(key)) + QQmlType type = it->type(key); + if (type.isValid()) return Result(type); } return Result(); } - QStringHash<Import> m_namedImports; - QMap<const Import *, QStringHash<Import> > m_namespacedImports; + QStringHash<QQmlImportRef> m_namedImports; + QMap<const QQmlImportRef *, QStringHash<QQmlImportRef> > m_namespacedImports; QVector<QQmlTypeModuleVersion> m_anonymousImports; QStringHash<QUrl> m_anonymousCompositeSingletons; QQmlImports m_imports; }; QQmlTypeNameCache::Result::Result() -: type(0), importNamespace(0), scriptIndex(-1) +: importNamespace(0), scriptIndex(-1) { } -QQmlTypeNameCache::Result::Result(const void *importNamespace) -: type(0), importNamespace(importNamespace), scriptIndex(-1) +QQmlTypeNameCache::Result::Result(const QQmlImportRef *importNamespace) +: importNamespace(importNamespace), scriptIndex(-1) { } -QQmlTypeNameCache::Result::Result(QQmlType *type) +QQmlTypeNameCache::Result::Result(const QQmlType &type) : type(type), importNamespace(0), scriptIndex(-1) { } QQmlTypeNameCache::Result::Result(int scriptIndex) -: type(0), importNamespace(0), scriptIndex(scriptIndex) +: importNamespace(0), scriptIndex(scriptIndex) { } @@ -186,12 +188,7 @@ QQmlTypeNameCache::Result::Result(const Result &o) bool QQmlTypeNameCache::Result::isValid() const { - return type || importNamespace || scriptIndex != -1; -} - -QQmlTypeNameCache::Import::Import() -: scriptIndex(-1) -{ + return type.isValid() || importNamespace || scriptIndex != -1; } bool QQmlTypeNameCache::isEmpty() const diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 7a06077c11..404bc0612e 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -64,15 +64,22 @@ void Heap::QQmlTypeWrapper::init() void Heap::QQmlTypeWrapper::destroy() { + QQmlType::derefHandle(typePrivate); + typePrivate = nullptr; if (typeNamespace) typeNamespace->release(); object.destroy(); Object::destroy(); } +QQmlType Heap::QQmlTypeWrapper::type() const +{ + return QQmlType(typePrivate); +} + bool QQmlTypeWrapper::isSingleton() const { - return d()->type && d()->type->isSingleton(); + return d()->type().isSingleton(); } QObject* QQmlTypeWrapper::singletonObject() const @@ -81,22 +88,16 @@ QObject* QQmlTypeWrapper::singletonObject() const return 0; QQmlEngine *e = engine()->qmlEngine(); - QQmlType::SingletonInstanceInfo *siinfo = d()->type->singletonInstanceInfo(); + QQmlType::SingletonInstanceInfo *siinfo = d()->type().singletonInstanceInfo(); siinfo->init(e); return siinfo->qobjectApi(e); } QVariant QQmlTypeWrapper::toVariant() const { - if (d()->type && d()->type->isSingleton()) { - QQmlEngine *e = engine()->qmlEngine(); - QQmlType::SingletonInstanceInfo *siinfo = d()->type->singletonInstanceInfo(); - siinfo->init(e); // note: this will also create QJSValue singleton which isn't strictly required. - QObject *qobjectSingleton = siinfo->qobjectApi(e); - if (qobjectSingleton) { - return QVariant::fromValue<QObject*>(qobjectSingleton); - } - } + QObject *qobjectSingleton = singletonObject(); + if (qobjectSingleton) + return QVariant::fromValue<QObject*>(qobjectSingleton); // only QObject Singleton Type can be converted to a variant. return QVariant(); @@ -104,20 +105,22 @@ QVariant QQmlTypeWrapper::toVariant() const // Returns a type wrapper for type t on o. This allows access of enums, and attached properties. -ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, QQmlType *t, +ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, const QQmlType &t, Heap::QQmlTypeWrapper::TypeNameMode mode) { - Q_ASSERT(t); + Q_ASSERT(t.isValid()); Scope scope(engine); Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocObject<QQmlTypeWrapper>()); - w->d()->mode = mode; w->d()->object = o; w->d()->type = t; + w->d()->mode = mode; w->d()->object = o; + w->d()->typePrivate = t.priv(); + QQmlType::refHandle(w->d()->typePrivate); return w.asReturnedValue(); } // Returns a type wrapper for importNamespace (of t) on o. This allows nested resolution of a type in a // namespace. -ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, QQmlTypeNameCache *t, const void *importNamespace, +ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, QQmlTypeNameCache *t, const QQmlImportRef *importNamespace, Heap::QQmlTypeWrapper::TypeNameMode mode) { Q_ASSERT(t); @@ -131,10 +134,10 @@ ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, } static int enumForSingleton(QV4::ExecutionEngine *v4, String *name, QObject *qobjectSingleton, - QQmlType *type) + const QQmlType &type) { bool ok; - int value = type->enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok); + int value = type.enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok); if (ok) return value; @@ -150,11 +153,11 @@ static int enumForSingleton(QV4::ExecutionEngine *v4, String *name, QObject *qob return -1; } -static ReturnedValue throwLowercaseEnumError(QV4::ExecutionEngine *v4, String *name, QQmlType *type) +static ReturnedValue throwLowercaseEnumError(QV4::ExecutionEngine *v4, String *name, const QQmlType &type) { const QString message = QStringLiteral("Cannot access enum value '%1' of '%2', enum values need to start with an uppercase letter.") - .arg(name->toQString()).arg(QLatin1String(type->typeName())); + .arg(name->toQString()).arg(QLatin1String(type.typeName())); return v4->throwTypeError(message); } @@ -173,14 +176,14 @@ ReturnedValue QQmlTypeWrapper::get(const Managed *m, String *name, bool *hasProp QQmlContextData *context = v4->callingQmlContext(); QObject *object = w->d()->object; - QQmlType *type = w->d()->type; + QQmlType type = w->d()->type(); - if (type) { + if (type.isValid()) { // singleton types are handled differently to other types. - if (type->isSingleton()) { + if (type.isSingleton()) { QQmlEngine *e = v4->qmlEngine(); - QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo(); + QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo(); siinfo->init(e); QObject *qobjectSingleton = siinfo->qobjectApi(e); @@ -221,14 +224,15 @@ ReturnedValue QQmlTypeWrapper::get(const Managed *m, String *name, bool *hasProp if (name->startsWithUpper()) { bool ok = false; - int value = type->enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok); + int value = type.enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok); if (ok) return QV4::Primitive::fromInt32(value).asReturnedValue(); - value = type->scopedEnumIndex(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok); + value = type.scopedEnumIndex(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok); if (ok) { Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocObject<QQmlScopedEnumWrapper>()); - enumWrapper->d()->type = type; + enumWrapper->d()->typePrivate = type.priv(); + QQmlType::refHandle(enumWrapper->d()->typePrivate); enumWrapper->d()->scopeEnumIndex = value; return enumWrapper.asReturnedValue(); } @@ -236,7 +240,7 @@ ReturnedValue QQmlTypeWrapper::get(const Managed *m, String *name, bool *hasProp // Fall through to base implementation } else if (w->d()->object) { - QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(QQmlEnginePrivate::get(v4->qmlEngine())), object); + QObject *ao = qmlAttachedPropertiesObjectById(type.attachedPropertiesId(QQmlEnginePrivate::get(v4->qmlEngine())), object); if (ao) return QV4::QObjectWrapper::getQmlProperty(v4, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, hasProperty); @@ -253,7 +257,7 @@ ReturnedValue QQmlTypeWrapper::get(const Managed *m, String *name, bool *hasProp QQmlTypeNameCache::Result r = w->d()->typeNamespace->query(name, w->d()->importNamespace); if (r.isValid()) { - if (r.type) { + if (r.type.isValid()) { return create(scope.engine, object, r.type, w->d()->mode); } else if (r.scriptIndex != -1) { QV4::ScopedObject scripts(scope, context->importedScripts.valueRef()); @@ -278,9 +282,9 @@ ReturnedValue QQmlTypeWrapper::get(const Managed *m, String *name, bool *hasProp *hasProperty = ok; // Warn when attempting to access a lowercased enum value, non-singleton case - if (!ok && type && !type->isSingleton() && !name->startsWithUpper()) { + if (!ok && type.isValid() && !type.isSingleton() && !name->startsWithUpper()) { bool enumOk = false; - type->enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &enumOk); + type.enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &enumOk); if (enumOk) return throwLowercaseEnumError(v4, name, type); } @@ -300,17 +304,17 @@ bool QQmlTypeWrapper::put(Managed *m, String *name, const Value &value) QV4::Scope scope(v4); QQmlContextData *context = v4->callingQmlContext(); - QQmlType *type = w->d()->type; - if (type && !type->isSingleton() && w->d()->object) { + QQmlType type = w->d()->type(); + if (type.isValid() && !type.isSingleton() && w->d()->object) { QObject *object = w->d()->object; QQmlEngine *e = scope.engine->qmlEngine(); - QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(QQmlEnginePrivate::get(e)), object); + QObject *ao = qmlAttachedPropertiesObjectById(type.attachedPropertiesId(QQmlEnginePrivate::get(e)), object); if (ao) return QV4::QObjectWrapper::setQmlProperty(v4, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, value); return false; - } else if (type && type->isSingleton()) { + } else if (type.isSingleton()) { QQmlEngine *e = scope.engine->qmlEngine(); - QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo(); + QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo(); siinfo->init(e); QObject *qobjectSingleton = siinfo->qobjectApi(e); @@ -368,7 +372,7 @@ ReturnedValue QQmlTypeWrapper::instanceOf(const Object *typeObject, const Value if (!wrapperObject) return engine->throwTypeError(); - const int myTypeId = typeWrapper->d()->type->typeId(); + const int myTypeId = typeWrapper->d()->type().typeId(); QQmlMetaObject myQmlType; if (myTypeId == 0) { // we're a composite type; a composite type cannot be equal to a @@ -379,7 +383,7 @@ ReturnedValue QQmlTypeWrapper::instanceOf(const Object *typeObject, const Value if (!theirDData->compilationUnit) return Encode(false); - QQmlTypeData *td = qenginepriv->typeLoader.getType(typeWrapper->d()->type->sourceUrl()); + QQmlTypeData *td = qenginepriv->typeLoader.getType(typeWrapper->d()->type().sourceUrl()); CompiledData::CompilationUnit *cu = td->compilationUnit(); myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId); } else { @@ -391,6 +395,18 @@ ReturnedValue QQmlTypeWrapper::instanceOf(const Object *typeObject, const Value return QV4::Encode(QQmlMetaObject::canConvert(theirType, myQmlType)); } +void Heap::QQmlScopedEnumWrapper::destroy() +{ + QQmlType::derefHandle(typePrivate); + typePrivate = nullptr; + Object::destroy(); +} + +QQmlType Heap::QQmlScopedEnumWrapper::type() const +{ + return QQmlType(typePrivate); +} + ReturnedValue QQmlScopedEnumWrapper::get(const Managed *m, String *name, bool *hasProperty) { Q_ASSERT(m->as<QQmlScopedEnumWrapper>()); @@ -398,11 +414,11 @@ ReturnedValue QQmlScopedEnumWrapper::get(const Managed *m, String *name, bool *h QV4::ExecutionEngine *v4 = resource->engine(); QV4::Scope scope(v4); - QQmlType *type = resource->d()->type; + QQmlType type = resource->d()->type(); int index = resource->d()->scopeEnumIndex; bool ok = false; - int value = type->scopedEnumValue(QQmlEnginePrivate::get(v4->qmlEngine()), index, name, &ok); + int value = type.scopedEnumValue(QQmlEnginePrivate::get(v4->qmlEngine()), index, name, &ok); if (hasProperty) *hasProperty = ok; if (ok) diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h index d28751d10a..25ff7ba7c8 100644 --- a/src/qml/qml/qqmltypewrapper_p.h +++ b/src/qml/qml/qqmltypewrapper_p.h @@ -61,6 +61,8 @@ QT_BEGIN_NAMESPACE class QQmlTypeNameCache; class QQmlType; +class QQmlTypePrivate; +struct QQmlImportRef; namespace QV4 { @@ -77,16 +79,19 @@ struct QQmlTypeWrapper : Object { TypeNameMode mode; QQmlQPointer<QObject> object; - QQmlType *type; + QQmlType type() const; + + QQmlTypePrivate *typePrivate; QQmlTypeNameCache *typeNamespace; - const void *importNamespace; + const QQmlImportRef *importNamespace; }; struct QQmlScopedEnumWrapper : Object { void init() { Object::init(); } - void destroy() { Object::destroy(); } + void destroy(); int scopeEnumIndex; - QQmlType *type; + QQmlTypePrivate *typePrivate; + QQmlType type() const; }; } @@ -101,9 +106,9 @@ struct Q_QML_EXPORT QQmlTypeWrapper : Object QVariant toVariant() const; - static ReturnedValue create(ExecutionEngine *, QObject *, QQmlType *, + static ReturnedValue create(ExecutionEngine *, QObject *, const QQmlType &, Heap::QQmlTypeWrapper::TypeNameMode = Heap::QQmlTypeWrapper::IncludeEnums); - static ReturnedValue create(ExecutionEngine *, QObject *, QQmlTypeNameCache *, const void *, + static ReturnedValue create(ExecutionEngine *, QObject *, QQmlTypeNameCache *, const QQmlImportRef *, Heap::QQmlTypeWrapper::TypeNameMode = Heap::QQmlTypeWrapper::IncludeEnums); diff --git a/src/qml/qml/qqmlvaluetypeproxybinding.cpp b/src/qml/qml/qqmlvaluetypeproxybinding.cpp index 4e2e7b06c7..7a3e4b2df4 100644 --- a/src/qml/qml/qqmlvaluetypeproxybinding.cpp +++ b/src/qml/qml/qqmlvaluetypeproxybinding.cpp @@ -72,6 +72,11 @@ bool QQmlValueTypeProxyBinding::isValueTypeProxy() const return true; } +QQmlAbstractBinding *QQmlValueTypeProxyBinding::subBindings() const +{ + return m_bindings.data(); +} + QQmlAbstractBinding *QQmlValueTypeProxyBinding::binding(QQmlPropertyIndex propertyIndex) const { QQmlAbstractBinding *binding = m_bindings.data(); diff --git a/src/qml/qml/qqmlvaluetypeproxybinding_p.h b/src/qml/qml/qqmlvaluetypeproxybinding_p.h index 92b5470f39..ba0d305bd9 100644 --- a/src/qml/qml/qqmlvaluetypeproxybinding_p.h +++ b/src/qml/qml/qqmlvaluetypeproxybinding_p.h @@ -60,6 +60,7 @@ class QQmlValueTypeProxyBinding : public QQmlAbstractBinding public: QQmlValueTypeProxyBinding(QObject *o, QQmlPropertyIndex coreIndex); + QQmlAbstractBinding *subBindings() const; QQmlAbstractBinding *binding(QQmlPropertyIndex targetPropertyIndex) const; void removeBindings(quint32 mask); diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 7e6fa2ee67..c784adb845 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -313,24 +313,25 @@ QAbstractDynamicMetaObject *QQmlInterceptorMetaObject::toDynamicMetaObject(QObje return this; } -QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj, +QQmlVMEMetaObject::QQmlVMEMetaObject(QV4::ExecutionEngine *engine, + QObject *obj, QQmlPropertyCache *cache, QV4::CompiledData::CompilationUnit *qmlCompilationUnit, int qmlObjectId) : QQmlInterceptorMetaObject(obj, cache), + engine(engine), ctxt(QQmlData::get(obj, true)->outerContext), aliasEndpoints(0), compilationUnit(qmlCompilationUnit), compiledObject(0) { + Q_ASSERT(engine); QQmlData::get(obj)->hasVMEMetaObject = true; if (compilationUnit && qmlObjectId >= 0) { compiledObject = compilationUnit->data->objectAt(qmlObjectId); if (compiledObject->nProperties || compiledObject->nFunctions) { - Q_ASSERT(cache && cache->engine); - QV4::ExecutionEngine *v4 = cache->engine; uint size = compiledObject->nProperties + compiledObject->nFunctions; if (size) { - QV4::Heap::MemberData *data = QV4::MemberData::allocate(v4, size); - propertyAndMethodStorage.set(v4, data); + QV4::Heap::MemberData *data = QV4::MemberData::allocate(engine, size); + propertyAndMethodStorage.set(engine, data); std::fill(data->values.values, data->values.values + data->values.size, QV4::Encode::undefined()); } @@ -366,77 +367,77 @@ void QQmlVMEMetaObject::writeProperty(int id, int v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - md->set(cache->engine, id, QV4::Primitive::fromInt32(v)); + md->set(engine, id, QV4::Primitive::fromInt32(v)); } void QQmlVMEMetaObject::writeProperty(int id, bool v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - md->set(cache->engine, id, QV4::Primitive::fromBoolean(v)); + md->set(engine, id, QV4::Primitive::fromBoolean(v)); } void QQmlVMEMetaObject::writeProperty(int id, double v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - md->set(cache->engine, id, QV4::Primitive::fromDouble(v)); + md->set(engine, id, QV4::Primitive::fromDouble(v)); } void QQmlVMEMetaObject::writeProperty(int id, const QString& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - md->set(cache->engine, id, cache->engine->newString(v)); + md->set(engine, id, engine->newString(v)); } void QQmlVMEMetaObject::writeProperty(int id, const QUrl& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - md->set(cache->engine, id, cache->engine->newVariantObject(QVariant::fromValue(v))); + md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v))); } void QQmlVMEMetaObject::writeProperty(int id, const QDate& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - md->set(cache->engine, id, cache->engine->newVariantObject(QVariant::fromValue(v))); + md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v))); } void QQmlVMEMetaObject::writeProperty(int id, const QDateTime& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - md->set(cache->engine, id, cache->engine->newVariantObject(QVariant::fromValue(v))); + md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v))); } void QQmlVMEMetaObject::writeProperty(int id, const QPointF& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - md->set(cache->engine, id, cache->engine->newVariantObject(QVariant::fromValue(v))); + md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v))); } void QQmlVMEMetaObject::writeProperty(int id, const QSizeF& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - md->set(cache->engine, id, cache->engine->newVariantObject(QVariant::fromValue(v))); + md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v))); } void QQmlVMEMetaObject::writeProperty(int id, const QRectF& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - md->set(cache->engine, id, cache->engine->newVariantObject(QVariant::fromValue(v))); + md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v))); } void QQmlVMEMetaObject::writeProperty(int id, QObject* v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - md->set(cache->engine, id, QV4::Value::fromReturnedValue(QV4::QObjectWrapper::wrap(cache->engine, v))); + md->set(engine, id, QV4::Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, v))); QQmlVMEVariantQObjectPtr *guard = getQObjectGuardForProperty(id); if (v && !guard) { @@ -453,7 +454,7 @@ int QQmlVMEMetaObject::readPropertyAsInt(int id) const if (!md) return 0; - QV4::Scope scope(cache->engine); + QV4::Scope scope(engine); QV4::ScopedValue sv(scope, *(md->data() + id)); if (!sv->isInt32()) return 0; @@ -466,7 +467,7 @@ bool QQmlVMEMetaObject::readPropertyAsBool(int id) const if (!md) return false; - QV4::Scope scope(cache->engine); + QV4::Scope scope(engine); QV4::ScopedValue sv(scope, *(md->data() + id)); if (!sv->isBoolean()) return false; @@ -479,7 +480,7 @@ double QQmlVMEMetaObject::readPropertyAsDouble(int id) const if (!md) return 0.0; - QV4::Scope scope(cache->engine); + QV4::Scope scope(engine); QV4::ScopedValue sv(scope, *(md->data() + id)); if (!sv->isDouble()) return 0.0; @@ -492,7 +493,7 @@ QString QQmlVMEMetaObject::readPropertyAsString(int id) const if (!md) return QString(); - QV4::Scope scope(cache->engine); + QV4::Scope scope(engine); QV4::ScopedValue sv(scope, *(md->data() + id)); if (QV4::String *s = sv->stringValue()) return s->toQString(); @@ -505,7 +506,7 @@ QUrl QQmlVMEMetaObject::readPropertyAsUrl(int id) const if (!md) return QUrl(); - QV4::Scope scope(cache->engine); + QV4::Scope scope(engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::VariantObject *v = sv->as<QV4::VariantObject>(); if (!v || v->d()->data().type() != QVariant::Url) @@ -519,7 +520,7 @@ QDate QQmlVMEMetaObject::readPropertyAsDate(int id) const if (!md) return QDate(); - QV4::Scope scope(cache->engine); + QV4::Scope scope(engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::VariantObject *v = sv->as<QV4::VariantObject>(); if (!v || v->d()->data().type() != QVariant::Date) @@ -533,7 +534,7 @@ QDateTime QQmlVMEMetaObject::readPropertyAsDateTime(int id) if (!md) return QDateTime(); - QV4::Scope scope(cache->engine); + QV4::Scope scope(engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::VariantObject *v = sv->as<QV4::VariantObject>(); if (!v || v->d()->data().type() != QVariant::DateTime) @@ -547,7 +548,7 @@ QSizeF QQmlVMEMetaObject::readPropertyAsSizeF(int id) const if (!md) return QSizeF(); - QV4::Scope scope(cache->engine); + QV4::Scope scope(engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::VariantObject *v = sv->as<QV4::VariantObject>(); if (!v || v->d()->data().type() != QVariant::SizeF) @@ -561,7 +562,7 @@ QPointF QQmlVMEMetaObject::readPropertyAsPointF(int id) const if (!md) return QPointF(); - QV4::Scope scope(cache->engine); + QV4::Scope scope(engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::VariantObject *v = sv->as<QV4::VariantObject>(); if (!v || v->d()->data().type() != QVariant::PointF) @@ -575,7 +576,7 @@ QObject* QQmlVMEMetaObject::readPropertyAsQObject(int id) const if (!md) return 0; - QV4::Scope scope(cache->engine); + QV4::Scope scope(engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::QObjectWrapper *wrapper = sv->as<QV4::QObjectWrapper>(); if (!wrapper) @@ -589,12 +590,12 @@ QList<QObject *> *QQmlVMEMetaObject::readPropertyAsList(int id) const if (!md) return 0; - QV4::Scope scope(cache->engine); + QV4::Scope scope(engine); QV4::Scoped<QV4::VariantObject> v(scope, *(md->data() + id)); if (!v || (int)v->d()->data().userType() != qMetaTypeId<QList<QObject *> >()) { QVariant variant(qVariantFromValue(QList<QObject*>())); - v = cache->engine->newVariantObject(variant); - md->set(cache->engine, id, v); + v = engine->newVariantObject(variant); + md->set(engine, id, v); } return static_cast<QList<QObject *> *>(v->d()->data().data()); } @@ -605,7 +606,7 @@ QRectF QQmlVMEMetaObject::readPropertyAsRectF(int id) const if (!md) return QRectF(); - QV4::Scope scope(cache->engine); + QV4::Scope scope(engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::VariantObject *v = sv->as<QV4::VariantObject>(); if (!v || v->d()->data().type() != QVariant::RectF) @@ -819,7 +820,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) { const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); if (!v) { - md->set(cache->engine, id, cache->engine->newVariantObject(QVariant())); + md->set(engine, id, engine->newVariantObject(QVariant())); v = (md->data() + id)->as<QV4::VariantObject>(); QQml_valueTypeProvider()->initValueType(fallbackMetaType, v->d()->data()); } @@ -1016,7 +1017,7 @@ QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id) const const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); if (v) return v->d()->data(); - return cache->engine->toVariant(*(md->data() + id), -1); + return engine->toVariant(*(md->data() + id), -1); } return QVariant(); } @@ -1057,7 +1058,7 @@ void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value) guard->setGuardedValue(valueObject, this, id); // Write the value and emit change signal as appropriate. - md->set(cache->engine, id, value); + md->set(engine, id, value); activate(object, methodOffset() + id, 0); } @@ -1076,15 +1077,15 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) // And, if the new value is a scarce resource, we need to ensure that it does not get // automatically released by the engine until no other references to it exist. - QV4::Scope scope(cache->engine); - QV4::ScopedValue newv(scope, cache->engine->fromVariant(value)); + QV4::Scope scope(engine); + QV4::ScopedValue newv(scope, engine->fromVariant(value)); QV4::Scoped<QV4::VariantObject> v(scope, newv); if (!!v) v->addVmePropertyReference(); // Write the value and emit change signal as appropriate. QVariant currentValue = readPropertyAsVariant(id); - md->set(cache->engine, id, newv); + md->set(engine, id, newv); if ((currentValue.userType() != value.userType() || currentValue != value)) activate(object, methodOffset() + id, 0); } else { @@ -1102,7 +1103,7 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) v->d()->data() != value); if (v) v->removeVmePropertyReference(); - md->set(cache->engine, id, cache->engine->newVariantObject(value)); + md->set(engine, id, engine->newVariantObject(value)); v = static_cast<const QV4::VariantObject *>(md->data() + id); v->addVmePropertyReference(); } @@ -1142,7 +1143,7 @@ void QQmlVMEMetaObject::setVmeMethod(int index, const QV4::Value &function) QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return; - md->set(cache->engine, methodIndex + compiledObject->nProperties, function); + md->set(engine, methodIndex + compiledObject->nProperties, function); } QV4::ReturnedValue QQmlVMEMetaObject::vmeProperty(int index) const @@ -1166,15 +1167,13 @@ void QQmlVMEMetaObject::setVMEProperty(int index, const QV4::Value &v) void QQmlVMEMetaObject::ensureQObjectWrapper() { - Q_ASSERT(cache && cache->engine); - QV4::ExecutionEngine *v4 = cache->engine; - QV4::QObjectWrapper::wrap(v4, object); + Q_ASSERT(cache); + QV4::QObjectWrapper::wrap(engine, object); } void QQmlVMEMetaObject::mark(QV4::MarkStack *markStack) { - QV4::ExecutionEngine *v4 = cache ? cache->engine : 0; - if (v4 != markStack->engine) + if (engine != markStack->engine) return; propertyAndMethodStorage.markOnce(markStack); diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h index 031a9a9ddd..ea5e9c0904 100644 --- a/src/qml/qml/qqmlvmemetaobject_p.h +++ b/src/qml/qml/qqmlvmemetaobject_p.h @@ -144,7 +144,7 @@ class QQmlVMEMetaObjectEndpoint; class Q_QML_PRIVATE_EXPORT QQmlVMEMetaObject : public QQmlInterceptorMetaObject { public: - QQmlVMEMetaObject(QObject *obj, QQmlPropertyCache *cache, QV4::CompiledData::CompilationUnit *qmlCompilationUnit, int qmlObjectId); + QQmlVMEMetaObject(QV4::ExecutionEngine *engine, QObject *obj, QQmlPropertyCache *cache, QV4::CompiledData::CompilationUnit *qmlCompilationUnit, int qmlObjectId); ~QQmlVMEMetaObject(); bool aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const; @@ -164,6 +164,7 @@ protected: int metaCall(QObject *o, QMetaObject::Call _c, int _id, void **_a) Q_DECL_OVERRIDE; public: + QV4::ExecutionEngine *engine; QQmlGuardedContextData ctxt; inline int propOffset() const; diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index 526522cb10..023ecbbb64 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -1843,8 +1843,13 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_send(const BuiltinFunction *b, QV4: THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state"); QByteArray data; - if (callData->argc > 0) - data = callData->args[0].toQStringNoThrow().toUtf8(); + if (callData->argc > 0) { + if (const ArrayBuffer *buffer = callData->args[0].as<ArrayBuffer>()) { + data = buffer->asByteArray(); + } else { + data = callData->args[0].toQStringNoThrow().toUtf8(); + } + } return r->send(w, scope.engine->callingQmlContext(), data); } diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index 56188a4b7d..96c898e6d4 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -857,6 +857,8 @@ In addition the following expressions can be used to specify the time: \li use AM/PM display. \e AP will be replaced by either "AM" or "PM". \row \li ap \li use am/pm display. \e ap will be replaced by either "am" or "pm". + \row \li t + \li include a time-zone indicator. \endtable All other input characters will be ignored. Any sequence of characters that |