diff options
author | Laszlo Agocs <laszlo.agocs@theqtcompany.com> | 2016-05-24 11:08:09 +0200 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@theqtcompany.com> | 2016-05-24 11:33:42 +0200 |
commit | 9ff09fb283cd130fb717769b44f54bfbb28efd8a (patch) | |
tree | 711f70b4b494bd996d54bdab5c44f3c89b37a6d1 | |
parent | 592b5b49b6c0043fae5db7721689813ebd226032 (diff) | |
parent | ec2b2a5f5d804095b6b2b8575b1cd1b75a8335ff (diff) |
Merge remote-tracking branch 'origin/dev' into wip/scenegraphng
Conflicts:
src/quick/items/qquickopenglshadereffectnode.cpp
src/quick/items/qquickshadereffect.cpp
src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
src/quick/scenegraph/qsgdefaultglyphnode_p.h
Change-Id: I3d6874b4e4231a89d2836c04fe8e7f2ef2d698c4
221 files changed, 3761 insertions, 2032 deletions
diff --git a/examples/qml/qmlextensionplugins/plugin.cpp b/examples/qml/qmlextensionplugins/plugin.cpp index 56057b7f06..e04cfa57d8 100644 --- a/examples/qml/qmlextensionplugins/plugin.cpp +++ b/examples/qml/qmlextensionplugins/plugin.cpp @@ -141,7 +141,7 @@ MinuteTimer *TimeModel::timer=0; class QExampleQmlPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: void registerTypes(const char *uri) diff --git a/examples/qml/tutorials/extending-qml/chapter6-plugins/app.pro b/examples/qml/tutorials/extending-qml/chapter6-plugins/app.pro index c55db00d27..4d0e807417 100644 --- a/examples/qml/tutorials/extending-qml/chapter6-plugins/app.pro +++ b/examples/qml/tutorials/extending-qml/chapter6-plugins/app.pro @@ -1,10 +1,15 @@ TARGET = chapter6-plugins QT += qml quick -# Avoid going to debug/release subdirectory -# so that our application will see the -# import path for the Charts module. +# Ensure that the application will see the import path for the Charts module: +# * On Windows, do not build into a debug/release subdirectory. +# * On OS X, add the plugin files into the bundle. win32: DESTDIR = ./ +osx { + charts.files = $$OUT_PWD/Charts + charts.path = Contents/PlugIns + QMAKE_BUNDLE_DATA += charts +} SOURCES += main.cpp RESOURCES += app.qrc diff --git a/examples/qml/tutorials/extending-qml/chapter6-plugins/import/chartsplugin.h b/examples/qml/tutorials/extending-qml/chapter6-plugins/import/chartsplugin.h index 3c0f84fe34..2a9c2446bd 100644 --- a/examples/qml/tutorials/extending-qml/chapter6-plugins/import/chartsplugin.h +++ b/examples/qml/tutorials/extending-qml/chapter6-plugins/import/chartsplugin.h @@ -46,7 +46,7 @@ class ChartsPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: void registerTypes(const char *uri); diff --git a/examples/qml/tutorials/extending-qml/chapter6-plugins/main.cpp b/examples/qml/tutorials/extending-qml/chapter6-plugins/main.cpp index b20ae35f92..d165513861 100644 --- a/examples/qml/tutorials/extending-qml/chapter6-plugins/main.cpp +++ b/examples/qml/tutorials/extending-qml/chapter6-plugins/main.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -37,17 +37,21 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -//![0] #include <QtQuick/QQuickView> #include <QGuiApplication> +#include <QQmlEngine> int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); +//![0] QQuickView view; +#ifdef Q_OS_OSX + view.engine()->addImportPath(app.applicationDirPath() + "/../PlugIns"); +#endif +//![0] view.setResizeMode(QQuickView::SizeRootObjectToView); view.setSource(QUrl("qrc:///app.qml")); view.show(); return app.exec(); } -//![0] diff --git a/examples/quick/customitems/painteditem/TextBalloonPlugin/plugin.h b/examples/quick/customitems/painteditem/TextBalloonPlugin/plugin.h index 3a2ddae871..d3a1f4ba91 100644 --- a/examples/quick/customitems/painteditem/TextBalloonPlugin/plugin.h +++ b/examples/quick/customitems/painteditem/TextBalloonPlugin/plugin.h @@ -55,7 +55,7 @@ class TextBalloonPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: void registerTypes(const char *uri) { diff --git a/examples/quick/imageprovider/imageprovider.cpp b/examples/quick/imageprovider/imageprovider.cpp index f402ce0ce8..1e4f53e736 100644 --- a/examples/quick/imageprovider/imageprovider.cpp +++ b/examples/quick/imageprovider/imageprovider.cpp @@ -87,7 +87,7 @@ public: class ImageProviderExtensionPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: void registerTypes(const char *uri) { @@ -103,7 +103,4 @@ public: }; -#define QQmlExtensionInterface_iid "org.qt-project.Qt.QQmlExtensionInterface" - - #include "imageprovider.moc" diff --git a/examples/quick/imageresponseprovider/imageresponseprovider.cpp b/examples/quick/imageresponseprovider/imageresponseprovider.cpp index bdec29114b..a888c823a6 100644 --- a/examples/quick/imageresponseprovider/imageresponseprovider.cpp +++ b/examples/quick/imageresponseprovider/imageresponseprovider.cpp @@ -102,7 +102,7 @@ private: class ImageProviderExtensionPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: void registerTypes(const char *uri) { @@ -117,7 +117,4 @@ public: }; - -#define QQmlExtensionInterface_iid "org.qt-project.Qt.QQmlExtensionInterface" - #include "imageresponseprovider.moc" diff --git a/src/3rdparty/masm/wtf/Compiler.h b/src/3rdparty/masm/wtf/Compiler.h index b886f37151..fc3b5c5c08 100644 --- a/src/3rdparty/masm/wtf/Compiler.h +++ b/src/3rdparty/masm/wtf/Compiler.h @@ -74,12 +74,15 @@ /* COMPILER(MSVC) - Microsoft Visual C++ */ /* COMPILER(MSVC7_OR_LOWER) - Microsoft Visual C++ 2003 or lower*/ /* COMPILER(MSVC9_OR_LOWER) - Microsoft Visual C++ 2008 or lower*/ +/* COMPILER(MSVC12_OR_LOWER) - Microsoft Visual C++ 2013 or lower*/ #if defined(_MSC_VER) #define WTF_COMPILER_MSVC 1 #if _MSC_VER < 1400 #define WTF_COMPILER_MSVC7_OR_LOWER 1 #elif _MSC_VER < 1600 #define WTF_COMPILER_MSVC9_OR_LOWER 1 +#elif _MSC_VER < 1800 +#define WTF_COMPILER_MSVC12_OR_LOWER 1 #endif /* Specific compiler features */ diff --git a/src/3rdparty/masm/wtf/MathExtras.h b/src/3rdparty/masm/wtf/MathExtras.h index 9a85291ae2..9ded0ab736 100644 --- a/src/3rdparty/masm/wtf/MathExtras.h +++ b/src/3rdparty/masm/wtf/MathExtras.h @@ -173,11 +173,15 @@ inline float log2f(float num) inline long long abs(long long num) { return _abs64(num); } #endif +#if COMPILER(MSVC12_OR_LOWER) + inline double nextafter(double x, double y) { return _nextafter(x, y); } inline float nextafterf(float x, float y) { return x > y ? x - FLT_EPSILON : x + FLT_EPSILON; } inline double copysign(double x, double y) { return _copysign(x, y); } +#endif // COMPILER(MSVC12_OR_LOWER) + // Work around a bug in Win, where atan2(+-infinity, +-infinity) yields NaN instead of specific values. inline double wtf_atan2(double x, double y) { @@ -211,6 +215,8 @@ inline double wtf_pow(double x, double y) { return y == 0 ? 1 : pow(x, y); } #define fmod(x, y) wtf_fmod(x, y) #define pow(x, y) wtf_pow(x, y) +#if COMPILER(MSVC12_OR_LOWER) + // MSVC's math functions do not bring lrint. inline long int lrint(double flt) { @@ -233,6 +239,7 @@ inline long int lrint(double flt) return static_cast<long int>(intgr); } +#endif // COMPILER(MSVC12_OR_LOWER) #endif // COMPILER(MSVC) inline double deg2rad(double d) { return d * piDouble / 180.0; } diff --git a/src/imports/folderlistmodel/plugin.cpp b/src/imports/folderlistmodel/plugin.cpp index 38de232dc0..affde1c3aa 100644 --- a/src/imports/folderlistmodel/plugin.cpp +++ b/src/imports/folderlistmodel/plugin.cpp @@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE class QmlFolderListModelPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: QmlFolderListModelPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); } diff --git a/src/imports/layouts/plugin.cpp b/src/imports/layouts/plugin.cpp index 64d687cf3b..da5f264ab5 100644 --- a/src/imports/layouts/plugin.cpp +++ b/src/imports/layouts/plugin.cpp @@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE class QtQuickLayoutsPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: QtQuickLayoutsPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index 8780dcc757..3fd36f3f0d 100644 --- a/src/imports/localstorage/plugin.cpp +++ b/src/imports/localstorage/plugin.cpp @@ -754,7 +754,7 @@ static QObject *module_api_factory(QQmlEngine *engine, QJSEngine *scriptEngine) class QQmlLocalStoragePlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: QQmlLocalStoragePlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) diff --git a/src/imports/models/plugin.cpp b/src/imports/models/plugin.cpp index 046d69cbc5..dbb62cd25d 100644 --- a/src/imports/models/plugin.cpp +++ b/src/imports/models/plugin.cpp @@ -75,7 +75,7 @@ QT_BEGIN_NAMESPACE class QtQmlModelsPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: QtQmlModelsPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); } void registerTypes(const char *uri) Q_DECL_OVERRIDE diff --git a/src/imports/particles/plugin.cpp b/src/imports/particles/plugin.cpp index 22eea16d4c..28ce0f7796 100644 --- a/src/imports/particles/plugin.cpp +++ b/src/imports/particles/plugin.cpp @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE class QtQuick2ParticlesPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: QtQuick2ParticlesPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); } void registerTypes(const char *uri) Q_DECL_OVERRIDE diff --git a/src/imports/qtquick2/plugin.cpp b/src/imports/qtquick2/plugin.cpp index 1e3ff255f8..e56027c1bb 100644 --- a/src/imports/qtquick2/plugin.cpp +++ b/src/imports/qtquick2/plugin.cpp @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE class QtQuick2Plugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: QtQuick2Plugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); } void registerTypes(const char *uri) Q_DECL_OVERRIDE diff --git a/src/imports/settings/plugin.cpp b/src/imports/settings/plugin.cpp index ce498774d2..c422296446 100644 --- a/src/imports/settings/plugin.cpp +++ b/src/imports/settings/plugin.cpp @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE class QmlSettingsPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: QmlSettingsPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); } diff --git a/src/imports/statemachine/plugin.cpp b/src/imports/statemachine/plugin.cpp index c061607f40..ae32f6446a 100644 --- a/src/imports/statemachine/plugin.cpp +++ b/src/imports/statemachine/plugin.cpp @@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE class QtQmlStateMachinePlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtQml.StateMachine/1.0") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: QtQmlStateMachinePlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); } diff --git a/src/imports/testlib/main.cpp b/src/imports/testlib/main.cpp index 1632d7ba64..4e2bd919e9 100644 --- a/src/imports/testlib/main.cpp +++ b/src/imports/testlib/main.cpp @@ -147,7 +147,7 @@ QT_BEGIN_NAMESPACE class QTestQmlModule : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: QTestQmlModule(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); } diff --git a/src/imports/window/plugin.cpp b/src/imports/window/plugin.cpp index b85ccc6dc7..200f6f7b08 100644 --- a/src/imports/window/plugin.cpp +++ b/src/imports/window/plugin.cpp @@ -70,7 +70,7 @@ QT_BEGIN_NAMESPACE class QtQuick2WindowPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: QtQuick2WindowPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); } void registerTypes(const char *uri) Q_DECL_OVERRIDE diff --git a/src/imports/xmllistmodel/plugin.cpp b/src/imports/xmllistmodel/plugin.cpp index ca676c36b0..af7625c96a 100644 --- a/src/imports/xmllistmodel/plugin.cpp +++ b/src/imports/xmllistmodel/plugin.cpp @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE class QmlXmlListModelPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: QmlXmlListModelPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); } diff --git a/src/particles/qquickcustomparticle.cpp b/src/particles/qquickcustomparticle.cpp index 38c0b855e8..a89b0d6a3b 100644 --- a/src/particles/qquickcustomparticle.cpp +++ b/src/particles/qquickcustomparticle.cpp @@ -291,8 +291,6 @@ QQuickOpenGLShaderEffectNode *QQuickCustomParticle::prepareNextFrame(QQuickOpenG builder.appendSourceFile(QStringLiteral(":/particles/shaders/customparticle.vert")); s.sourceCode[Key::VertexShader] = builder.source() + s.sourceCode[Key::VertexShader]; - s.className = metaObject()->className(); - material->setProgramSource(s); material->attributes = m_common.attributes; foreach (QQuickOpenGLShaderEffectNode* node, m_nodes) diff --git a/src/particles/qquickparticleemitter_p.h b/src/particles/qquickparticleemitter_p.h index 9b114ad46b..dd55fdc7a6 100644 --- a/src/particles/qquickparticleemitter_p.h +++ b/src/particles/qquickparticleemitter_p.h @@ -322,6 +322,8 @@ public: return m_startTime; } + void reclaculateGroupId() const; + protected: qreal m_particlesPerSecond; int m_particleDuration; @@ -359,9 +361,6 @@ protected: bool isEmitConnected(); -private: // methods - void reclaculateGroupId() const; - private: // data QString m_group; mutable bool m_groupIdNeedRecalculation; diff --git a/src/particles/qquickparticlesystem.cpp b/src/particles/qquickparticlesystem.cpp index 17d9e49d63..b60180b2ed 100644 --- a/src/particles/qquickparticlesystem.cpp +++ b/src/particles/qquickparticlesystem.cpp @@ -597,6 +597,13 @@ void QQuickParticleSystem::initGroups() groupIds.clear(); nextFreeGroupId = 0; + for (auto e : qAsConst(m_emitters)) { + e->reclaculateGroupId(); + } + foreach (QQuickParticlePainter *p, m_painters) { + p->recalculateGroupIds(); + } + QQuickParticleGroupData *pd = new QQuickParticleGroupData(QString(), this); // Default group Q_ASSERT(pd->index == 0); Q_UNUSED(pd); diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp index a9996da7f4..e08436b7a3 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp @@ -683,11 +683,13 @@ bool QQmlEngineDebugServiceImpl::resetBinding(int objectId, const QString &prope QQmlContext *context = qmlContext(object); if (object && context) { - QString parentProperty = propertyName; - if (propertyName.indexOf(QLatin1Char('.')) != -1) - parentProperty = propertyName.left(propertyName.indexOf(QLatin1Char('.'))); + QStringRef parentPropertyRef(&propertyName); + const int idx = parentPropertyRef.indexOf(QLatin1Char('.')); + if (idx != -1) + parentPropertyRef = parentPropertyRef.left(idx); - if (object->property(parentProperty.toLatin1()).isValid()) { + const QByteArray parentProperty = parentPropertyRef.toLatin1(); + if (object->property(parentProperty).isValid()) { QQmlProperty property(object, propertyName); QQmlPropertyPrivate::removeBinding(property); if (property.isResettable()) { @@ -700,7 +702,7 @@ bool QQmlEngineDebugServiceImpl::resetBinding(int objectId, const QString &prope // overwrite with default value if (QQmlType *objType = QQmlMetaType::qmlType(object->metaObject())) { if (QObject *emptyObject = objType->create()) { - if (emptyObject->property(parentProperty.toLatin1()).isValid()) { + if (emptyObject->property(parentProperty).isValid()) { QVariant defaultValue = QQmlProperty(emptyObject, propertyName).read(); if (defaultValue.isValid()) { setBinding(objectId, propertyName, defaultValue, true); @@ -764,9 +766,14 @@ bool QQmlEngineDebugServiceImpl::setMethodBody(int objectId, const QString &meth QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(object); Q_ASSERT(vmeMetaObject); // the fact we found the property above should guarentee this - int lineNumber = vmeMetaObject->vmeMethodLineNumber(prop->coreIndex); QV4::ExecutionEngine *v4 = QV8Engine::getV4(qmlEngine(object)->handle()); QV4::Scope scope(v4); + + int lineNumber = 0; + QV4::ScopedFunctionObject oldMethod(scope, vmeMetaObject->vmeMethod(prop->coreIndex)); + if (oldMethod && oldMethod->d()->function) { + lineNumber = oldMethod->d()->function->compiledFunction->location.line; + } QV4::ScopedValue v(scope, QQmlJavaScriptExpression::evalFunction(contextData, object, jsfunction, contextData->urlString(), lineNumber)); vmeMetaObject->setVmeMethod(prop->coreIndex, v); return true; diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp index 075f56226d..99f5b760ba 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp @@ -704,7 +704,7 @@ bool NativeDebugger::reallyHitTheBreakPoint(const QV4::Function *function, int l const BreakPoint &bp = m_service->m_breakHandler->m_breakPoints.at(i); if (bp.lineNumber == lineNumber) { const QString fileName = function->sourceFile(); - const QString base = fileName.mid(fileName.lastIndexOf('/') + 1); + const QStringRef base = fileName.midRef(fileName.lastIndexOf('/') + 1); if (bp.fileName.endsWith(base)) { if (bp.condition.isEmpty() || checkCondition(bp.condition)) { BreakPoint &mbp = m_service->m_breakHandler->m_breakPoints[i]; diff --git a/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.cpp b/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.cpp index cc0118f0c2..3145601612 100644 --- a/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.cpp +++ b/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.cpp @@ -49,6 +49,7 @@ #include <QtCore/qjsonobject.h> #include <QtCore/qjsonvalue.h> #include <QtCore/qpointer.h> +#include <QtCore/qvector.h> //#define TRACE_PROTOCOL(s) qDebug() << s #define TRACE_PROTOCOL(s) @@ -182,24 +183,21 @@ QQmlNativeDebugConnector::QQmlNativeDebugConnector() : m_blockingMode(false) { const QString args = commandLineArguments(); - const QStringList lstjsDebugArguments = args.split(QLatin1Char(',')); + const auto lstjsDebugArguments = args.splitRef(QLatin1Char(',')); QStringList services; - QStringList::const_iterator argsItEnd = lstjsDebugArguments.cend(); - QStringList::const_iterator argsIt = lstjsDebugArguments.cbegin(); - for (; argsIt != argsItEnd; ++argsIt) { - const QString strArgument = *argsIt; + for (const QStringRef &strArgument : lstjsDebugArguments) { if (strArgument == QLatin1String("block")) { m_blockingMode = true; } else if (strArgument == QLatin1String("native")) { // Ignore. This is used to signal that this connector // should be loaded and that has already happened. } else if (strArgument.startsWith(QLatin1String("services:"))) { - services.append(strArgument.mid(9)); + services.append(strArgument.mid(9).toString()); } else if (!services.isEmpty()) { - services.append(strArgument); + services.append(strArgument.toString()); } else { qWarning("QML Debugger: Invalid argument \"%s\" detected. Ignoring the same.", - qUtf8Printable(strArgument)); + strArgument.toUtf8().constData()); } } setServices(services); diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp index 688ced26ec..a193ddea0b 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp @@ -58,71 +58,81 @@ QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEngin connect(this, SIGNAL(dataRequested()), engine->profiler, SLOT(reportData())); connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)), engine->profiler, SLOT(setTimer(QElapsedTimer))); - connect(engine->profiler, SIGNAL(dataReady(QVector<QQmlProfilerData>)), - this, SLOT(receiveData(QVector<QQmlProfilerData>))); + connect(engine->profiler, + SIGNAL(dataReady(QVector<QQmlProfilerData>,QQmlProfiler::LocationHash)), + this, + SLOT(receiveData(QVector<QQmlProfilerData>,QQmlProfiler::LocationHash))); } // convert to QByteArrays that can be sent to the debug client // use of QDataStream can skew results // (see tst_qqmldebugtrace::trace() benchmark) -static void qQmlProfilerDataToByteArrays(const QQmlProfilerData *d, QList<QByteArray> &messages) +static void qQmlProfilerDataToByteArrays(const QQmlProfilerData &d, + const QQmlProfiler::LocationHash &locations, + QList<QByteArray> &messages) { QQmlDebugPacket ds; - Q_ASSERT_X(((d->messageType | d->detailType) & (1 << 31)) == 0, Q_FUNC_INFO, - "You can use at most 31 message types and 31 detail types."); - for (uint decodedMessageType = 0; (d->messageType >> decodedMessageType) != 0; + Q_ASSERT_X((d.messageType & (1 << 31)) == 0, Q_FUNC_INFO, + "You can use at most 31 message types."); + for (quint32 decodedMessageType = 0; (d.messageType >> decodedMessageType) != 0; ++decodedMessageType) { - if ((d->messageType & (1 << decodedMessageType)) == 0) + if ((d.messageType & (1 << decodedMessageType)) == 0) continue; - for (uint decodedDetailType = 0; (d->detailType >> decodedDetailType) != 0; - ++decodedDetailType) { - if ((d->detailType & (1 << decodedDetailType)) == 0) - continue; + //### using QDataStream is relatively expensive + ds << d.time << decodedMessageType << static_cast<quint32>(d.detailType); - //### using QDataStream is relatively expensive - ds << d->time << decodedMessageType << decodedDetailType; + QQmlProfiler::Location l = locations.value(d.locationId); - switch (decodedMessageType) { - case QQmlProfilerDefinitions::RangeStart: - case QQmlProfilerDefinitions::RangeEnd: - break; - case QQmlProfilerDefinitions::RangeData: - ds << (d->detailString.isEmpty() ? d->detailUrl.toString() : d->detailString); - break; - case QQmlProfilerDefinitions::RangeLocation: - ds << (d->detailUrl.isEmpty() ? d->detailString : d->detailUrl.toString()) << d->x - << d->y; - break; - default: - Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid message type."); - break; - } - messages.append(ds.squeezedData()); - ds.clear(); + switch (decodedMessageType) { + case QQmlProfilerDefinitions::RangeStart: + case QQmlProfilerDefinitions::RangeEnd: + break; + case QQmlProfilerDefinitions::RangeData: + ds << (l.location.sourceFile.isEmpty() ? l.url.toString() : l.location.sourceFile); + break; + case QQmlProfilerDefinitions::RangeLocation: + ds << (l.url.isEmpty() ? l.location.sourceFile : l.url.toString()) + << static_cast<qint32>(l.location.line) << static_cast<qint32>(l.location.column); + break; + default: + Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid message type."); + break; } + messages.append(ds.squeezedData()); + ds.clear(); } } qint64 QQmlProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages) { while (next != data.length()) { - if (data[next].time > until || messages.length() > s_numMessagesPerBatch) - return data[next].time; - qQmlProfilerDataToByteArrays(&(data[next++]), messages); + const QQmlProfilerData &nextData = data.at(next); + if (nextData.time > until || messages.length() > s_numMessagesPerBatch) + return nextData.time; + qQmlProfilerDataToByteArrays(nextData, locations, messages); + ++next; } next = 0; data.clear(); + locations.clear(); return -1; } -void QQmlProfilerAdapter::receiveData(const QVector<QQmlProfilerData> &new_data) +void QQmlProfilerAdapter::receiveData(const QVector<QQmlProfilerData> &new_data, + const QQmlProfiler::LocationHash &new_locations) { if (data.isEmpty()) data = new_data; else data.append(new_data); + + if (locations.isEmpty()) + locations = new_locations; + else + locations.unite(new_locations); + service->dataReady(this); } diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h index 2d93efba1b..7e13b6c479 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h @@ -63,10 +63,12 @@ public: qint64 sendMessages(qint64 until, QList<QByteArray> &messages) Q_DECL_OVERRIDE; public slots: - void receiveData(const QVector<QQmlProfilerData> &new_data); + void receiveData(const QVector<QQmlProfilerData> &new_data, + const QQmlProfiler::LocationHash &locations); private: QVector<QQmlProfilerData> data; + QQmlProfiler::LocationHash locations; int next; }; diff --git a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp index b50eef5545..68a71a5524 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp +++ b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp @@ -61,29 +61,35 @@ QV4ProfilerAdapter::QV4ProfilerAdapter(QQmlProfilerService *service, QV4::Execut connect(this, SIGNAL(dataRequested()), engine->profiler, SLOT(reportData())); connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)), engine->profiler, SLOT(setTimer(QElapsedTimer))); - connect(engine->profiler, SIGNAL(dataReady(QVector<QV4::Profiling::FunctionCallProperties>, + connect(engine->profiler, SIGNAL(dataReady(QV4::Profiling::FunctionLocationHash, + QVector<QV4::Profiling::FunctionCallProperties>, QVector<QV4::Profiling::MemoryAllocationProperties>)), - this, SLOT(receiveData(QVector<QV4::Profiling::FunctionCallProperties>, + this, SLOT(receiveData(QV4::Profiling::FunctionLocationHash, + QVector<QV4::Profiling::FunctionCallProperties>, QVector<QV4::Profiling::MemoryAllocationProperties>))); } qint64 QV4ProfilerAdapter::appendMemoryEvents(qint64 until, QList<QByteArray> &messages, QQmlDebugPacket &d) { - while (m_memoryData.length() > m_memoryPos && m_memoryData[m_memoryPos].timestamp <= until) { - QV4::Profiling::MemoryAllocationProperties &props = m_memoryData[m_memoryPos]; + // Make it const, so that we cannot accidentally detach it. + const QVector<QV4::Profiling::MemoryAllocationProperties> &memoryData = m_memoryData; + + while (memoryData.length() > m_memoryPos && memoryData[m_memoryPos].timestamp <= until) { + const QV4::Profiling::MemoryAllocationProperties &props = memoryData[m_memoryPos]; d << props.timestamp << MemoryAllocation << props.type << props.size; ++m_memoryPos; messages.append(d.squeezedData()); d.clear(); } - return m_memoryData.length() == m_memoryPos ? -1 : m_memoryData[m_memoryPos].timestamp; + return memoryData.length() == m_memoryPos ? -1 : memoryData[m_memoryPos].timestamp; } qint64 QV4ProfilerAdapter::finalizeMessages(qint64 until, QList<QByteArray> &messages, qint64 callNext, QQmlDebugPacket &d) { if (callNext == -1) { + m_functionLocations.clear(); m_functionCallData.clear(); m_functionCallPos = 0; } @@ -102,10 +108,15 @@ qint64 QV4ProfilerAdapter::finalizeMessages(qint64 until, QList<QByteArray> &mes qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages) { QQmlDebugPacket d; + + // Make it const, so that we cannot accidentally detach it. + const QVector<QV4::Profiling::FunctionCallProperties> &functionCallData = m_functionCallData; + const QV4::Profiling::FunctionLocationHash &functionLocations = m_functionLocations; + while (true) { while (!m_stack.isEmpty() && - (m_functionCallPos == m_functionCallData.length() || - m_stack.top() <= m_functionCallData[m_functionCallPos].start)) { + (m_functionCallPos == functionCallData.length() || + m_stack.top() <= functionCallData[m_functionCallPos].start)) { if (m_stack.top() > until || messages.length() > s_numMessagesPerBatch) return finalizeMessages(until, messages, m_stack.top(), d); @@ -114,39 +125,46 @@ qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &message messages.append(d.squeezedData()); d.clear(); } - while (m_functionCallPos != m_functionCallData.length() && - (m_stack.empty() || m_functionCallData[m_functionCallPos].start < m_stack.top())) { + while (m_functionCallPos != functionCallData.length() && + (m_stack.empty() || functionCallData[m_functionCallPos].start < m_stack.top())) { const QV4::Profiling::FunctionCallProperties &props = - m_functionCallData[m_functionCallPos]; + functionCallData[m_functionCallPos]; if (props.start > until || messages.length() > s_numMessagesPerBatch) return finalizeMessages(until, messages, props.start, d); appendMemoryEvents(props.start, messages, d); + auto location = functionLocations.constFind(props.id); + Q_ASSERT(location != functionLocations.constEnd()); d << props.start << RangeStart << Javascript; messages.push_back(d.squeezedData()); d.clear(); - d << props.start << RangeLocation << Javascript << props.file << props.line - << props.column; + d << props.start << RangeLocation << Javascript << location->file << location->line + << location->column; messages.push_back(d.squeezedData()); d.clear(); - d << props.start << RangeData << Javascript << props.name; + d << props.start << RangeData << Javascript << location->name; messages.push_back(d.squeezedData()); d.clear(); m_stack.push(props.end); ++m_functionCallPos; } - if (m_stack.empty() && m_functionCallPos == m_functionCallData.length()) + if (m_stack.empty() && m_functionCallPos == functionCallData.length()) return finalizeMessages(until, messages, -1, d); } } void QV4ProfilerAdapter::receiveData( + const QV4::Profiling::FunctionLocationHash &locations, const QVector<QV4::Profiling::FunctionCallProperties> &functionCallData, const QVector<QV4::Profiling::MemoryAllocationProperties> &memoryData) { // In rare cases it could be that another flush or stop event is processed while data from // the previous one is still pending. In that case we just append the data. + if (m_functionLocations.isEmpty()) + m_functionLocations = locations; + else + m_functionLocations.unite(locations); if (m_functionCallData.isEmpty()) m_functionCallData = functionCallData; diff --git a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h index f2985af98b..968825c346 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h +++ b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h @@ -74,7 +74,8 @@ signals: void v4ProfilingEnabledWhileWaiting(quint64 v4Features); public slots: - void receiveData(const QVector<QV4::Profiling::FunctionCallProperties> &, + void receiveData(const QV4::Profiling::FunctionLocationHash &, + const QVector<QV4::Profiling::FunctionCallProperties> &, const QVector<QV4::Profiling::MemoryAllocationProperties> &); private slots: @@ -82,6 +83,7 @@ private slots: void forwardEnabledWhileWaiting(quint64 features); private: + QV4::Profiling::FunctionLocationHash m_functionLocations; QVector<QV4::Profiling::FunctionCallProperties> m_functionCallData; QVector<QV4::Profiling::MemoryAllocationProperties> m_memoryData; int m_functionCallPos; diff --git a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp index bc259afaa4..a6d93e85ae 100644 --- a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp +++ b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp @@ -53,6 +53,7 @@ #include <QtCore/QDir> #include <QtCore/QPluginLoader> #include <QtCore/QStringList> +#include <QtCore/QVector> #include <QtCore/qwaitcondition.h> QT_BEGIN_NAMESPACE @@ -345,40 +346,40 @@ void QQmlDebugServerImpl::parseArguments() QString fileName; QStringList services; - const QStringList lstjsDebugArguments = args.split(QLatin1Char(',')); - QStringList::const_iterator argsItEnd = lstjsDebugArguments.cend(); - QStringList::const_iterator argsIt = lstjsDebugArguments.cbegin(); - for (; argsIt != argsItEnd; ++argsIt) { - const QString strArgument = *argsIt; + const auto lstjsDebugArguments = args.splitRef(QLatin1Char(',')); + for (auto argsIt = lstjsDebugArguments.begin(), argsItEnd = lstjsDebugArguments.end(); argsIt != argsItEnd; ++argsIt) { + const QStringRef &strArgument = *argsIt; if (strArgument.startsWith(QLatin1String("port:"))) { - portFrom = strArgument.midRef(5).toInt(&ok); + portFrom = strArgument.mid(5).toInt(&ok); portTo = portFrom; - QStringList::const_iterator argsNext = argsIt + 1; + const auto argsNext = argsIt + 1; if (argsNext == argsItEnd) break; - const QString nextArgument = *argsNext; - - // Don't use QStringLiteral here. QRegExp has a global cache and will save an implicitly - // shared copy of the passed string. That copy isn't properly detached when the library - // is unloaded if the original string lives in the library's .rodata - if (ok && nextArgument.contains(QRegExp(QLatin1String("^\\s*\\d+\\s*$")))) { - portTo = nextArgument.toInt(&ok); - ++argsIt; + if (ok) { + const QString nextArgument = argsNext->toString(); + + // Don't use QStringLiteral here. QRegExp has a global cache and will save an implicitly + // shared copy of the passed string. That copy isn't properly detached when the library + // is unloaded if the original string lives in the library's .rodata + if (nextArgument.contains(QRegExp(QLatin1String("^\\s*\\d+\\s*$")))) { + portTo = nextArgument.toInt(&ok); + ++argsIt; + } } } else if (strArgument.startsWith(QLatin1String("host:"))) { - hostAddress = strArgument.mid(5); + hostAddress = strArgument.mid(5).toString(); } else if (strArgument == QLatin1String("block")) { block = true; } else if (strArgument.startsWith(QLatin1String("file:"))) { - fileName = strArgument.mid(5); + fileName = strArgument.mid(5).toString(); ok = !fileName.isEmpty(); } else if (strArgument.startsWith(QLatin1String("services:"))) { - services.append(strArgument.mid(9)); + services.append(strArgument.mid(9).toString()); } else if (!services.isEmpty()) { - services.append(strArgument); + services.append(strArgument.toString()); } else { const QString message = tr("QML Debugger: Invalid argument \"%1\" detected." - " Ignoring the same.").arg(strArgument); + " Ignoring the same.").arg(strArgument.toString()); qWarning("%s", qPrintable(message)); } } @@ -423,7 +424,7 @@ void QQmlDebugServerImpl::parseArguments() //: Please preserve the line breaks and formatting << tr("Sends qDebug() and similar messages over the QML debug\n" "\t\t connection. QtCreator uses this for showing debug\n" - "\t\t messages in the JavaScript console.") << '\n' + "\t\t messages in the debugger console.") << '\n' << tr("Other services offered by qmltooling plugins that implement " "QQmlDebugServiceFactory and which can be found in the standard plugin " "paths will also be available and can be specified. If no \"services\" " diff --git a/src/plugins/qmltooling/shared/qqmlconfigurabledebugservice.h b/src/plugins/qmltooling/shared/qqmlconfigurabledebugservice.h index 668ce2558d..85ff9b182f 100644 --- a/src/plugins/qmltooling/shared/qqmlconfigurabledebugservice.h +++ b/src/plugins/qmltooling/shared/qqmlconfigurabledebugservice.h @@ -72,7 +72,7 @@ protected: { QMutexLocker lock(&m_configMutex); m_waitingForConfiguration = false; - foreach (QJSEngine *engine, m_waitingEngines) + for (QJSEngine *engine : qAsConst(m_waitingEngines)) emit Base::attachedToEngine(engine); m_waitingEngines.clear(); } diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index d4757bed39..a1713dd809 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -80,8 +80,10 @@ void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int id, const QQm location.column = loc.startColumn; idIndex = id; - indexOfDefaultProperty = -1; + indexOfDefaultPropertyOrAlias = -1; + defaultPropertyIsAlias = false; properties = pool->New<PoolList<Property> >(); + aliases = pool->New<PoolList<Alias> >(); qmlSignals = pool->New<PoolList<Signal> >(); bindings = pool->New<PoolList<Binding> >(); functions = pool->New<PoolList<Function> >(); @@ -145,15 +147,42 @@ QString Object::appendProperty(Property *prop, const QString &propertyName, bool const int index = target->properties->append(prop); if (isDefaultProperty) { - if (target->indexOfDefaultProperty != -1) { + if (target->indexOfDefaultPropertyOrAlias != -1) { *errorLocation = defaultToken; return tr("Duplicate default property"); } - target->indexOfDefaultProperty = index; + target->indexOfDefaultPropertyOrAlias = index; } return QString(); // no error } +QString Object::appendAlias(Alias *alias, const QString &aliasName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation) +{ + Object *target = declarationsOverride; + if (!target) + target = this; + + for (Alias *p = target->aliases->first; p; p = p->next) + if (p->nameIndex == alias->nameIndex) + return tr("Duplicate alias name"); + + if (aliasName.constData()->isUpper()) + return tr("Alias names cannot begin with an upper case letter"); + + const int index = target->aliases->append(alias); + + if (isDefaultProperty) { + if (target->indexOfDefaultPropertyOrAlias != -1) { + *errorLocation = defaultToken; + return tr("Duplicate default property"); + } + target->indexOfDefaultPropertyOrAlias = index; + target->defaultPropertyIsAlias = true; + } + + return QString(); // no error +} + void Object::appendFunction(QmlIR::Function *f) { Object *target = declarationsOverride; @@ -190,7 +219,7 @@ Binding *Object::findBinding(quint32 nameIndex) const void Object::insertSorted(Binding *b) { - Binding *insertionPoint = bindings->findSortedInsertionPoint<QV4::CompiledData::Location, QV4::CompiledData::Binding, &QV4::CompiledData::Binding::valueLocation>(b); + Binding *insertionPoint = bindings->findSortedInsertionPoint<quint32, Binding, &Binding::offset>(b); bindings->insertAfter(insertionPoint, b); } @@ -249,8 +278,8 @@ void Document::collectTypeReferences() void Document::removeScriptPragmas(QString &script) { - const QString pragma(QLatin1String("pragma")); - const QString library(QLatin1String("library")); + const QLatin1String pragma("pragma"); + const QLatin1String library("library"); QQmlJS::Lexer l(0); l.setCode(script, 0); @@ -268,7 +297,7 @@ void Document::removeScriptPragmas(QString &script) if (token != QQmlJSGrammar::T_PRAGMA || l.tokenStartLine() != startLine || - script.mid(l.tokenOffset(), l.tokenLength()) != pragma) + script.midRef(l.tokenOffset(), l.tokenLength()) != pragma) return; token = l.lex(); @@ -277,7 +306,7 @@ void Document::removeScriptPragmas(QString &script) l.tokenStartLine() != startLine) return; - QString pragmaValue = script.mid(l.tokenOffset(), l.tokenLength()); + const QStringRef pragmaValue = script.midRef(l.tokenOffset(), l.tokenLength()); int endOffset = l.tokenLength() + l.tokenOffset(); token = l.lex(); @@ -806,130 +835,86 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node) } } else { const QStringRef &memberType = node->memberType; - const QStringRef &name = node->name; - - bool typeFound = false; - QV4::CompiledData::Property::Type type; - if (memberType == QLatin1String("alias")) { - type = QV4::CompiledData::Property::Alias; - typeFound = true; - } + return appendAlias(node); + } else { + const QStringRef &name = node->name; - for (int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) { - const TypeNameToType *t = propTypeNameToTypes + ii; - if (memberType == QLatin1String(t->name, static_cast<int>(t->nameLength))) { - type = t->type; - typeFound = true; + bool typeFound = false; + QV4::CompiledData::Property::Type type; + + for (int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) { + const TypeNameToType *t = propTypeNameToTypes + ii; + if (memberType == QLatin1String(t->name, static_cast<int>(t->nameLength))) { + type = t->type; + typeFound = true; + } } - } - if (!typeFound && memberType.at(0).isUpper()) { - const QStringRef &typeModifier = node->typeModifier; + if (!typeFound && memberType.at(0).isUpper()) { + const QStringRef &typeModifier = node->typeModifier; - if (typeModifier.isEmpty()) { - type = QV4::CompiledData::Property::Custom; - } else if (typeModifier == QLatin1String("list")) { - type = QV4::CompiledData::Property::CustomList; - } else { - recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Invalid property type modifier")); + if (typeModifier.isEmpty()) { + type = QV4::CompiledData::Property::Custom; + } else if (typeModifier == QLatin1String("list")) { + type = QV4::CompiledData::Property::CustomList; + } else { + recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Invalid property type modifier")); + return false; + } + typeFound = true; + } else if (!node->typeModifier.isNull()) { + recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Unexpected property type modifier")); return false; } - typeFound = true; - } else if (!node->typeModifier.isNull()) { - recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Unexpected property type modifier")); - return false; - } - - if (!typeFound) { - recordError(node->typeToken, QCoreApplication::translate("QQmlParser","Expected property type")); - return false; - } - - Property *property = New<Property>(); - property->flags = 0; - if (node->isReadonlyMember) - property->flags |= QV4::CompiledData::Property::IsReadOnly; - property->type = type; - if (type >= QV4::CompiledData::Property::Custom) - property->customTypeNameIndex = registerString(memberType.toString()); - else - property->customTypeNameIndex = emptyStringIndex; - const QString propName = name.toString(); - property->nameIndex = registerString(propName); - - QQmlJS::AST::SourceLocation loc = node->firstSourceLocation(); - property->location.line = loc.startLine; - property->location.column = loc.startColumn; - - property->aliasPropertyValueIndex = emptyStringIndex; - - if (type == QV4::CompiledData::Property::Alias) { - if (!node->statement && !node->binding) - COMPILE_EXCEPTION(loc, tr("No property alias location")); + if (!typeFound) { + recordError(node->typeToken, QCoreApplication::translate("QQmlParser","Expected property type")); + return false; + } - QQmlJS::AST::SourceLocation rhsLoc; - if (node->binding) - rhsLoc = node->binding->firstSourceLocation(); - else if (node->statement) - rhsLoc = node->statement->firstSourceLocation(); + Property *property = New<Property>(); + property->flags = 0; + if (node->isReadonlyMember) + property->flags |= QV4::CompiledData::Property::IsReadOnly; + property->type = type; + if (type >= QV4::CompiledData::Property::Custom) + property->customTypeNameIndex = registerString(memberType.toString()); else - rhsLoc = node->semicolonToken; - property->aliasLocation.line = rhsLoc.startLine; - property->aliasLocation.column = rhsLoc.startColumn; - - QStringList alias; - - if (QQmlJS::AST::ExpressionStatement *stmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement*>(node->statement)) { - alias = astNodeToStringList(stmt->expression); - if (alias.isEmpty()) { - if (isStatementNodeScript(node->statement)) { - COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>")); - } else { - COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias location")); - } - } - } else { - COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>")); - } + property->customTypeNameIndex = emptyStringIndex; - if (alias.count() < 1 || alias.count() > 3) - COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>")); + const QString propName = name.toString(); + property->nameIndex = registerString(propName); - property->aliasIdValueIndex = registerString(alias.first()); + QQmlJS::AST::SourceLocation loc = node->firstSourceLocation(); + property->location.line = loc.startLine; + property->location.column = loc.startColumn; - QString propertyValue = alias.value(1); - if (alias.count() == 3) { - propertyValue += QLatin1Char('.'); - propertyValue += alias.at(2); - } - property->aliasPropertyValueIndex = registerString(propertyValue); - } - QQmlJS::AST::SourceLocation errorLocation; - QString error; + QQmlJS::AST::SourceLocation errorLocation; + QString error; - if (illegalNames.contains(propName)) - error = tr("Illegal property name"); - else - error = _object->appendProperty(property, propName, node->isDefaultMember, node->defaultToken, &errorLocation); + if (illegalNames.contains(propName)) + error = tr("Illegal property name"); + else + error = _object->appendProperty(property, propName, node->isDefaultMember, node->defaultToken, &errorLocation); - if (!error.isEmpty()) { - if (errorLocation.startLine == 0) - errorLocation = node->identifierToken; + if (!error.isEmpty()) { + if (errorLocation.startLine == 0) + errorLocation = node->identifierToken; - recordError(errorLocation, error); - return false; - } + recordError(errorLocation, error); + return false; + } - qSwap(_propertyDeclaration, property); - if (node->binding) { - // process QML-like initializers (e.g. property Object o: Object {}) - QQmlJS::AST::Node::accept(node->binding, this); - } else if (node->statement && type != QV4::CompiledData::Property::Alias) { - appendBinding(node->identifierToken, node->identifierToken, _propertyDeclaration->nameIndex, node->statement); + qSwap(_propertyDeclaration, property); + if (node->binding) { + // process QML-like initializers (e.g. property Object o: Object {}) + QQmlJS::AST::Node::accept(node->binding, this); + } else if (node->statement) { + appendBinding(node->identifierToken, node->identifierToken, _propertyDeclaration->nameIndex, node->statement); + } + qSwap(_propertyDeclaration, property); } - qSwap(_propertyDeclaration, property); } return false; @@ -1084,6 +1069,7 @@ void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLo { Binding *binding = New<Binding>(); binding->propertyNameIndex = propertyNameIndex; + binding->offset = nameLocation.offset; binding->location.line = nameLocation.startLine; binding->location.column = nameLocation.startColumn; binding->flags = 0; @@ -1103,6 +1089,7 @@ void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLo Binding *binding = New<Binding>(); binding->propertyNameIndex = propertyNameIndex; + binding->offset = nameLocation.offset; binding->location.line = nameLocation.startLine; binding->location.column = nameLocation.startColumn; @@ -1132,6 +1119,79 @@ void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLo } } +bool IRBuilder::appendAlias(QQmlJS::AST::UiPublicMember *node) +{ + Alias *alias = New<Alias>(); + alias->flags = 0; + if (node->isReadonlyMember) + alias->flags |= QV4::CompiledData::Alias::IsReadOnly; + + const QString propName = node->name.toString(); + alias->nameIndex = registerString(propName); + + QQmlJS::AST::SourceLocation loc = node->firstSourceLocation(); + alias->location.line = loc.startLine; + alias->location.column = loc.startColumn; + + alias->propertyNameIndex = emptyStringIndex; + + if (!node->statement && !node->binding) + COMPILE_EXCEPTION(loc, tr("No property alias location")); + + QQmlJS::AST::SourceLocation rhsLoc; + if (node->binding) + rhsLoc = node->binding->firstSourceLocation(); + else if (node->statement) + rhsLoc = node->statement->firstSourceLocation(); + else + rhsLoc = node->semicolonToken; + alias->referenceLocation.line = rhsLoc.startLine; + alias->referenceLocation.column = rhsLoc.startColumn; + + QStringList aliasReference; + + if (QQmlJS::AST::ExpressionStatement *stmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement*>(node->statement)) { + aliasReference = astNodeToStringList(stmt->expression); + if (aliasReference.isEmpty()) { + if (isStatementNodeScript(node->statement)) { + COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>")); + } else { + COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias location")); + } + } + } else { + COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>")); + } + + if (aliasReference.count() < 1 || aliasReference.count() > 3) + COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>")); + + alias->idIndex = registerString(aliasReference.first()); + + QString propertyValue = aliasReference.value(1); + if (aliasReference.count() == 3) + propertyValue += QLatin1Char('.') + aliasReference.at(2); + alias->propertyNameIndex = registerString(propertyValue); + + QQmlJS::AST::SourceLocation errorLocation; + QString error; + + if (illegalNames.contains(propName)) + error = tr("Illegal property name"); + else + error = _object->appendAlias(alias, propName, node->isDefaultMember, node->defaultToken, &errorLocation); + + if (!error.isEmpty()) { + if (errorLocation.startLine == 0) + errorLocation = node->identifierToken; + + recordError(errorLocation, error); + return false; + } + + return false; +} + Object *IRBuilder::bindingsTarget() const { if (_propertyDeclaration && _object->declarationsOverride) @@ -1201,8 +1261,7 @@ bool IRBuilder::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, O if (import->qualifierIndex != emptyStringIndex && stringAt(import->qualifierIndex) == currentName) { qualifiedIdElement = qualifiedIdElement->next; - currentName += QLatin1Char('.'); - currentName += qualifiedIdElement->name; + currentName += QLatin1Char('.') + qualifiedIdElement->name; if (!qualifiedIdElement->name.unicode()->isUpper()) COMPILE_EXCEPTION(qualifiedIdElement->firstSourceLocation(), tr("Expected type name")); @@ -1228,6 +1287,7 @@ bool IRBuilder::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, O if (!binding) { binding = New<Binding>(); binding->propertyNameIndex = propertyNameIndex; + binding->offset = qualifiedIdElement->identifierToken.offset; binding->location.line = qualifiedIdElement->identifierToken.startLine; binding->location.column = qualifiedIdElement->identifierToken.startColumn; binding->valueLocation.line = qualifiedIdElement->next->identifierToken.startLine; @@ -1313,7 +1373,7 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output) int objectsSize = 0; foreach (Object *o, output.objects) { objectOffsets.insert(o, unitSize + importSize + objectOffsetTableSize + objectsSize); - objectsSize += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->signalCount(), o->bindingCount()); + objectsSize += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->aliasCount(), o->signalCount(), o->bindingCount()); int signalTableSize = 0; for (const Signal *s = o->firstSignal(); s; s = s->next) @@ -1358,7 +1418,8 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output) QV4::CompiledData::Object *objectToWrite = reinterpret_cast<QV4::CompiledData::Object*>(objectPtr); objectToWrite->inheritedTypeNameIndex = o->inheritedTypeNameIndex; - objectToWrite->indexOfDefaultProperty = o->indexOfDefaultProperty; + objectToWrite->indexOfDefaultPropertyOrAlias = o->indexOfDefaultPropertyOrAlias; + objectToWrite->defaultPropertyIsAlias = o->defaultPropertyIsAlias; objectToWrite->idIndex = o->idIndex; objectToWrite->location = o->location; objectToWrite->locationOfIdProperty = o->locationOfIdProperty; @@ -1373,6 +1434,10 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output) objectToWrite->offsetToProperties = nextOffset; nextOffset += objectToWrite->nProperties * sizeof(QV4::CompiledData::Property); + objectToWrite->nAliases = o->aliasCount(); + objectToWrite->offsetToAliases = nextOffset; + nextOffset += objectToWrite->nAliases * sizeof(QV4::CompiledData::Alias); + objectToWrite->nSignals = o->signalCount(); objectToWrite->offsetToSignals = nextOffset; nextOffset += objectToWrite->nSignals * sizeof(quint32); @@ -1392,6 +1457,13 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output) propertiesPtr += sizeof(QV4::CompiledData::Property); } + char *aliasesPtr = objectPtr + objectToWrite->offsetToAliases; + for (const Alias *a = o->firstAlias(); a; a = a->next) { + QV4::CompiledData::Alias *aliasToWrite = reinterpret_cast<QV4::CompiledData::Alias*>(aliasesPtr); + *aliasToWrite = *a; + aliasesPtr += sizeof(QV4::CompiledData::Alias); + } + char *bindingPtr = objectPtr + objectToWrite->offsetToBindings; bindingPtr = writeBindings(bindingPtr, o, &QV4::CompiledData::Binding::isValueBindingNoAlias); bindingPtr = writeBindings(bindingPtr, o, &QV4::CompiledData::Binding::isSignalHandler); @@ -1420,7 +1492,7 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output) signalPtr += size; } - objectPtr += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->signalCount(), o->bindingCount()); + objectPtr += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->aliasCount(), o->signalCount(), o->bindingCount()); objectPtr += signalTableSize; } diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index 057ed1be9f..c53004a331 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -113,7 +113,7 @@ struct PoolList T *insertPos = 0; for (T *it = first; it; it = it->next) { - if (!(it->*sortMember < item->*sortMember)) + if (!(it->*sortMember <= item->*sortMember)) break; insertPos = it; } @@ -227,10 +227,19 @@ struct Property : public QV4::CompiledData::Property struct Binding : public QV4::CompiledData::Binding { + // The offset in the source file where the binding appeared. This is used for sorting to ensure + // that assignments to list properties are done in the correct order. We use the offset here instead + // of Binding::location as the latter has limited precision. + quint32 offset; // Binding's compiledScriptIndex is index in object's functionsAndExpressions Binding *next; }; +struct Alias : public QV4::CompiledData::Alias +{ + Alias *next; +}; + struct Function { QQmlJS::AST::FunctionDeclaration *functionDeclaration; @@ -266,13 +275,16 @@ struct Q_QML_PRIVATE_EXPORT Object public: quint32 inheritedTypeNameIndex; quint32 idIndex; - int indexOfDefaultProperty; + int indexOfDefaultPropertyOrAlias : 31; + int defaultPropertyIsAlias : 1; QV4::CompiledData::Location location; QV4::CompiledData::Location locationOfIdProperty; const Property *firstProperty() const { return properties->first; } int propertyCount() const { return properties->count; } + Alias *firstAlias() const { return aliases->first; } + int aliasCount() const { return aliases->count; } const Signal *firstSignal() const { return qmlSignals->first; } int signalCount() const { return qmlSignals->count; } Binding *firstBinding() const { return bindings->first; } @@ -290,6 +302,7 @@ public: QString appendSignal(Signal *signal); QString appendProperty(Property *prop, const QString &propertyName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation); + QString appendAlias(Alias *prop, const QString &aliasName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation); void appendFunction(QmlIR::Function *f); QString appendBinding(Binding *b, bool isListBinding); @@ -305,6 +318,7 @@ private: friend struct IRLoader; PoolList<Property> *properties; + PoolList<Alias> *aliases; PoolList<Signal> *qmlSignals; PoolList<Binding> *bindings; PoolList<Function> *functions; @@ -410,6 +424,8 @@ public: void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, QQmlJS::AST::Statement *value); void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, int objectIndex, bool isListItem = false, bool isOnAssignment = false); + bool appendAlias(QQmlJS::AST::UiPublicMember *node); + Object *bindingsTarget() const; bool setId(const QQmlJS::AST::SourceLocation &idLocation, QQmlJS::AST::Statement *value); diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index a71793f2b6..097d072734 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -179,16 +179,16 @@ bool QQmlTypeCompiler::compile() for (int scriptIndex = 0; scriptIndex < scripts.count(); ++scriptIndex) { const QQmlTypeData::ScriptReference &script = scripts.at(scriptIndex); - QString qualifier = script.qualifier; + QStringRef qualifier(&script.qualifier); QString enclosingNamespace; const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.')); if (lastDotIndex != -1) { - enclosingNamespace = qualifier.left(lastDotIndex); + enclosingNamespace = qualifier.left(lastDotIndex).toString(); qualifier = qualifier.mid(lastDotIndex+1); } - compiledData->importCache->add(qualifier, scriptIndex, enclosingNamespace); + compiledData->importCache->add(qualifier.toString(), scriptIndex, enclosingNamespace); QQmlScriptData *scriptData = script.script->scriptData(); scriptData->addref(); compiledData->scripts << scriptData; @@ -480,7 +480,7 @@ bool QQmlPropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int r } } - bool needVMEMetaObject = obj->propertyCount() != 0 || obj->signalCount() != 0 || obj->functionCount() != 0; + bool needVMEMetaObject = obj->propertyCount() != 0 || obj->aliasCount() != 0 || obj->signalCount() != 0 || obj->functionCount() != 0; if (!needVMEMetaObject) { for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { if (binding->type == QV4::CompiledData::Binding::Type_Object && (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)) { @@ -507,7 +507,7 @@ bool QQmlPropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int r Q_ASSERT(typeRef); if (typeRef->isFullyDynamicType) { - if (obj->propertyCount() > 0) { + if (obj->propertyCount() > 0 || obj->aliasCount() > 0) { recordError(obj->location, tr("Fully dynamic types cannot declare new properties.")); return false; } @@ -586,9 +586,9 @@ bool QQmlPropertyCacheCreator::ensureMetaObject(int objectIndex) bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Object *obj, QQmlPropertyCache *baseTypeCache) { - QQmlPropertyCache *cache = baseTypeCache->copyAndReserve(obj->propertyCount(), - obj->functionCount() + obj->propertyCount() + obj->signalCount(), - obj->signalCount() + obj->propertyCount()); + QQmlPropertyCache *cache = baseTypeCache->copyAndReserve(obj->propertyCount() + obj->aliasCount(), + obj->functionCount() + obj->propertyCount() + obj->aliasCount() + obj->signalCount(), + obj->signalCount() + obj->propertyCount() + obj->aliasCount()); propertyCaches[objectIndex] = cache; struct TypeData { @@ -624,7 +624,7 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob QString path = compiler->url().path(); int lastSlash = path.lastIndexOf(QLatin1Char('/')); if (lastSlash > -1) { - QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5); + const QStringRef nameBase = path.midRef(lastSlash + 1, path.length() - lastSlash - 5); if (!nameBase.isEmpty() && nameBase.at(0).isUpper()) newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)); @@ -638,30 +638,30 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob cache->_dynamicClassName = newClassName; - int aliasCount = 0; int varPropCount = 0; QmlIR::PropertyResolver resolver(baseTypeCache); for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next) { - if (p->type == QV4::CompiledData::Property::Alias) - aliasCount++; - else if (p->type == QV4::CompiledData::Property::Var) + if (p->type == QV4::CompiledData::Property::Var) varPropCount++; - // No point doing this for both the alias and non alias cases bool notInRevision = false; QQmlPropertyData *d = resolver.property(stringAt(p->nameIndex), ¬InRevision); if (d && d->isFinal()) COMPILE_EXCEPTION(p, tr("Cannot override FINAL property")); } + for (const QmlIR::Alias *a = obj->firstAlias(); a; a = a->next) { + bool notInRevision = false; + QQmlPropertyData *d = resolver.property(stringAt(a->nameIndex), ¬InRevision); + if (d && d->isFinal()) + COMPILE_EXCEPTION(a, tr("Cannot override FINAL property")); + } + typedef QQmlVMEMetaData VMD; - QByteArray &dynamicData = vmeMetaObjects[objectIndex] = QByteArray(sizeof(QQmlVMEMetaData) - + obj->propertyCount() * sizeof(VMD::PropertyData) - + obj->functionCount() * sizeof(VMD::MethodData) - + aliasCount * sizeof(VMD::AliasData), 0); + vmeMetaObjects[objectIndex] = QByteArray(sizeof(QQmlVMEMetaData) + obj->aliasCount() * sizeof(VMD::AliasData), 0); int effectivePropertyIndex = cache->propertyIndexCacheStart; int effectiveMethodIndex = cache->methodIndexCacheStart; @@ -689,25 +689,25 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob } } - // First set up notify signals for properties - first normal, then var, then alias - enum { NSS_Normal = 0, NSS_Alias = 1 }; - for (int ii = NSS_Normal; ii <= NSS_Alias; ++ii) { // 0 == normal, 1 == var, 2 == alias + // Set up notify signals for properties - first normal, then alias + for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next) { + quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction | + QQmlPropertyData::IsVMESignal; - if (ii == NSS_Alias && aliasCount == 0) continue; + QString changedSigName = stringAt(p->nameIndex) + QLatin1String("Changed"); + seenSignals.insert(changedSigName); - for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next) { - if ((ii == NSS_Normal && p->type == QV4::CompiledData::Property::Alias) || - (ii == NSS_Alias && p->type != QV4::CompiledData::Property::Alias)) - continue; + cache->appendSignal(changedSigName, flags, effectiveMethodIndex++); + } - quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction | - QQmlPropertyData::IsVMESignal; + for (const QmlIR::Alias *a = obj->firstAlias(); a; a = a->next) { + quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction | + QQmlPropertyData::IsVMESignal; - QString changedSigName = stringAt(p->nameIndex) + QLatin1String("Changed"); - seenSignals.insert(changedSigName); + QString changedSigName = stringAt(a->nameIndex) + QLatin1String("Changed"); + seenSignals.insert(changedSigName); - cache->appendSignal(changedSigName, flags, effectiveMethodIndex++); - } + cache->appendSignal(changedSigName, flags, effectiveMethodIndex++); } // Dynamic signals @@ -752,8 +752,6 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob } } - ((QQmlVMEMetaData *)dynamicData.data())->signalCount++; - quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMESignal; if (paramCount) @@ -795,25 +793,18 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob } - // Dynamic properties (except var and aliases) + // Dynamic properties int effectiveSignalIndex = cache->signalHandlerIndexCacheStart; int propertyIdx = 0; for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next, ++propertyIdx) { - - if (p->type == QV4::CompiledData::Property::Alias) - continue; - int propertyType = 0; - int vmePropertyType = 0; quint32 propertyFlags = 0; if (p->type == QV4::CompiledData::Property::Var) { propertyType = QMetaType::QVariant; - vmePropertyType = QQmlVMEMetaData::VarPropertyType; propertyFlags = QQmlPropertyData::IsVarProperty; } else if (p->type < builtinTypeCount) { propertyType = builtinTypes[p->type].metaType; - vmePropertyType = propertyType; if (p->type == QV4::CompiledData::Property::Variant) propertyFlags |= QQmlPropertyData::IsQVariant; @@ -836,20 +827,16 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob if (p->type == QV4::CompiledData::Property::Custom) { propertyType = data->metaTypeId; - vmePropertyType = QMetaType::QObjectStar; } else { propertyType = data->listMetaTypeId; - vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >(); } tdata->release(); } else { if (p->type == QV4::CompiledData::Property::Custom) { propertyType = qmltype->typeId(); - vmePropertyType = QMetaType::QObjectStar; } else { propertyType = qmltype->qListTypeId(); - vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >(); } } @@ -864,38 +851,12 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob QString propertyName = stringAt(p->nameIndex); - if (propertyIdx == obj->indexOfDefaultProperty) cache->_defaultPropertyName = propertyName; + if (!obj->defaultPropertyIsAlias && propertyIdx == obj->indexOfDefaultPropertyOrAlias) + cache->_defaultPropertyName = propertyName; cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, propertyType, effectiveSignalIndex); effectiveSignalIndex++; - - VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); - (vmd->propertyData() + vmd->propertyCount)->propertyType = vmePropertyType; - vmd->propertyCount++; - } - - // Alias property count. Actual data is setup in buildDynamicMetaAliases - ((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount; - - // Dynamic slot data - comes after the property data - for (const QmlIR::Function *s = obj->firstFunction(); s; s = s->next) { - QQmlJS::AST::FunctionDeclaration *astFunction = s->functionDeclaration; - int formalsCount = 0; - QQmlJS::AST::FormalParameterList *param = astFunction->formals; - while (param) { - formalsCount++; - param = param->next; - } - - VMD::MethodData methodData = { /* runtimeFunctionIndex*/ 0, // ### - formalsCount, - /* s->location.start.line */0 }; // ### - - VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); - VMD::MethodData &md = *(vmd->methodData() + vmd->methodCount); - vmd->methodCount++; - md = methodData; } return true; @@ -1163,10 +1124,10 @@ struct StaticQtMetaObject : public QObject { return &staticQtMetaObject; } }; -bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, const QString &enumName, int enumValue, bool isQtObject) +bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, const QStringRef &enumName, int enumValue, bool isQtObject) { if (enumName.length() > 0 && enumName[0].isLower() && !isQtObject) { - COMPILE_EXCEPTION(binding, tr("Invalid property assignment: Enum value \"%1\" cannot start with a lowercase letter").arg(enumName)); + COMPILE_EXCEPTION(binding, tr("Invalid property assignment: Enum value \"%1\" cannot start with a lowercase letter").arg(enumName.toString())); } binding->type = QV4::CompiledData::Binding::Type_Number; binding->value.d = (double)enumValue; @@ -1197,7 +1158,7 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj, QHashedStringRef typeName(string.constData(), dot); const bool isQtObject = (typeName == QLatin1String("Qt")); - QString enumValue = string.mid(dot+1); + const QStringRef enumValue = string.midRef(dot + 1); if (isIntProp) { // Allow enum assignment to ints. @@ -1318,7 +1279,7 @@ void QQmlAliasAnnotator::annotateBindingsToAliases() const QmlIR::Object *obj = qmlObjects.at(i); QmlIR::PropertyResolver resolver(propertyCache); - QQmlPropertyData *defaultProperty = obj->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty(); + QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty(); for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { if (!binding->isValueBinding()) @@ -1350,7 +1311,7 @@ void QQmlScriptStringScanner::scan() const QmlIR::Object *obj = qmlObjects.at(i); QmlIR::PropertyResolver resolver(propertyCache); - QQmlPropertyData *defaultProperty = obj->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty(); + QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty(); for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { if (binding->type != QV4::CompiledData::Binding::Type_Script) @@ -1390,7 +1351,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI { QmlIR::PropertyResolver propertyResolver(propertyCache); - QQmlPropertyData *defaultProperty = obj->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty(); + QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty(); for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { if (binding->type != QV4::CompiledData::Binding::Type_Object) @@ -1497,7 +1458,7 @@ bool QQmlComponentAndAliasResolver::resolve() if (obj->functionCount() > 0) COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions.")); - if (obj->propertyCount() > 0) + if (obj->propertyCount() > 0 || obj->aliasCount() > 0) COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties.")); if (obj->signalCount() > 0) COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals.")); @@ -1568,12 +1529,8 @@ bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex) _objectIndexToIdInScope->insert(objectIndex, _objectIndexToIdInScope->count()); } - for (const QmlIR::Property *property = obj->firstProperty(); property; property = property->next) { - if (property->type == QV4::CompiledData::Property::Alias) { - _objectsWithAliases.append(objectIndex); - break; - } - } + if (obj->aliasCount() > 0) + _objectsWithAliases.append(objectIndex); for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { if (binding->type != QV4::CompiledData::Binding::Type_Object @@ -1604,21 +1561,20 @@ bool QQmlComponentAndAliasResolver::resolveAliases() int effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.count(); int effectiveAliasIndex = 0; - const QmlIR::Property *p = obj->firstProperty(); - for (int propertyIndex = 0; propertyIndex < obj->propertyCount(); ++propertyIndex, p = p->next) { - if (p->type != QV4::CompiledData::Property::Alias) - continue; - - const int idIndex = p->aliasIdValueIndex; + int aliasIndex = 0; + for (QmlIR::Alias *alias = obj->firstAlias(); alias; alias = alias->next, ++aliasIndex) { + const int idIndex = alias->idIndex; const int targetObjectIndex = _idToObjectIndex.value(idIndex, -1); if (targetObjectIndex == -1) { - recordError(p->aliasLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex))); + recordError(alias->referenceLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex))); return false; } - const int targetId = _objectIndexToIdInScope->value(targetObjectIndex, -1); - Q_ASSERT(targetId != -1); + Q_ASSERT(!(alias->flags & QV4::CompiledData::Alias::Resolved)); + alias->flags |= QV4::CompiledData::Alias::Resolved; + Q_ASSERT(_objectIndexToIdInScope->contains(targetObjectIndex)); + alias->targetObjectId = _objectIndexToIdInScope->value(targetObjectIndex); - const QString aliasPropertyValue = stringAt(p->aliasPropertyValueIndex); + const QString aliasPropertyValue = stringAt(alias->propertyNameIndex); QStringRef property; QStringRef subProperty; @@ -1631,9 +1587,7 @@ bool QQmlComponentAndAliasResolver::resolveAliases() property = QStringRef(&aliasPropertyValue, 0, aliasPropertyValue.length()); int propIdx = -1; - int propType = 0; int notifySignal = -1; - int flags = 0; int type = 0; bool writable = false; bool resettable = false; @@ -1650,7 +1604,7 @@ bool QQmlComponentAndAliasResolver::resolveAliases() else type = typeRef->component->metaTypeId; - flags |= QML_ALIAS_FLAG_PTR; + alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject; propertyFlags |= QQmlPropertyData::IsQObjectDerived; } else { QQmlPropertyCache *targetCache = propertyCaches.at(targetObjectIndex); @@ -1659,7 +1613,7 @@ bool QQmlComponentAndAliasResolver::resolveAliases() QQmlPropertyData *targetProperty = resolver.property(property.toString()); if (!targetProperty || targetProperty->coreIndex > 0x0000FFFF) { - recordError(p->aliasLocation, tr("Invalid alias target location: %1").arg(property.toString())); + recordError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(property.toString())); return false; } @@ -1673,16 +1627,14 @@ bool QQmlComponentAndAliasResolver::resolveAliases() if (!subProperty.isEmpty()) { const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(type); if (!valueTypeMetaObject) { - recordError(p->aliasLocation, tr("Invalid alias target location: %1").arg(subProperty.toString())); + recordError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString())); return false; } - propType = type; - int valueTypeIndex = valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData()); if (valueTypeIndex == -1) { - recordError(p->aliasLocation, tr("Invalid alias target location: %1").arg(subProperty.toString())); + recordError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString())); return false; } Q_ASSERT(valueTypeIndex <= 0x0000FFFF); @@ -1704,12 +1656,13 @@ bool QQmlComponentAndAliasResolver::resolveAliases() propertyFlags |= QQmlPropertyData::IsQVariant; if (targetProperty->isQObject()) - flags |= QML_ALIAS_FLAG_PTR; + alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject; } } } - QQmlVMEMetaData::AliasData aliasData = { targetId, propIdx, propType, flags, notifySignal }; + alias->encodedMetaPropertyIndex = propIdx; + QQmlVMEMetaData::AliasData aliasData = { notifySignal }; typedef QQmlVMEMetaData VMD; QByteArray &dynamicData = (*vmeMetaObjectData)[objectIndex]; @@ -1719,7 +1672,7 @@ bool QQmlComponentAndAliasResolver::resolveAliases() Q_ASSERT(dynamicData.isDetached()); - if (!(p->flags & QV4::CompiledData::Property::IsReadOnly) && writable) + if (!(alias->flags & QV4::CompiledData::Property::IsReadOnly) && writable) propertyFlags |= QQmlPropertyData::IsWritable; else propertyFlags &= ~QQmlPropertyData::IsWritable; @@ -1729,8 +1682,11 @@ bool QQmlComponentAndAliasResolver::resolveAliases() else propertyFlags &= ~QQmlPropertyData::IsResettable; - QString propertyName = stringAt(p->nameIndex); - if (propertyIndex == obj->indexOfDefaultProperty) propertyCache->_defaultPropertyName = propertyName; + QString propertyName = stringAt(alias->nameIndex); + + if (obj->defaultPropertyIsAlias && aliasIndex == obj->indexOfDefaultPropertyOrAlias) + propertyCache->_defaultPropertyName = propertyName; + propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, type, effectiveSignalIndex++); @@ -1842,7 +1798,7 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD QString defaultPropertyName; QQmlPropertyData *defaultProperty = 0; - if (obj->indexOfDefaultProperty != -1) { + if (obj->indexOfDefaultPropertyOrAlias != -1) { QQmlPropertyCache *cache = propertyCache->parent(); defaultPropertyName = cache->defaultPropertyName(); defaultProperty = cache->defaultProperty(); @@ -2562,7 +2518,7 @@ void QQmlDefaultPropertyMerger::mergeDefaultProperties(int objectIndex) QmlIR::Object *object = qmlObjects.at(objectIndex); - QString defaultProperty = object->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultPropertyName() : propertyCache->defaultPropertyName(); + QString defaultProperty = object->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultPropertyName() : propertyCache->defaultPropertyName(); QmlIR::Binding *bindingsToReinsert = 0; QmlIR::Binding *tail = 0; diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h index 240f591f91..273ba01a88 100644 --- a/src/qml/compiler/qqmltypecompiler_p.h +++ b/src/qml/compiler/qqmltypecompiler_p.h @@ -196,7 +196,11 @@ public: bool resolveEnumBindings(); private: - bool assignEnumToBinding(QmlIR::Binding *binding, const QString &enumName, int enumValue, bool isQtObject); + bool assignEnumToBinding(QmlIR::Binding *binding, const QStringRef &enumName, int enumValue, bool isQtObject); + bool assignEnumToBinding(QmlIR::Binding *binding, const QString &enumName, int enumValue, bool isQtObject) + { + return assignEnumToBinding(binding, QStringRef(&enumName), enumValue, isQtObject); + } bool tryQualifiedEnumAssignment(const QmlIR::Object *obj, const QQmlPropertyCache *propertyCache, const QQmlPropertyData *prop, QmlIR::Binding *binding); diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 4d0361302e..ded2c1a9f8 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -72,6 +72,9 @@ CompilationUnit::CompilationUnit() CompilationUnit::~CompilationUnit() { unlink(); + if (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) + free(data); + data = 0; } QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) @@ -163,9 +166,6 @@ void CompilationUnit::unlink() if (engine) engine->compilationUnits.erase(engine->compilationUnits.find(this)); engine = 0; - if (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) - free(data); - data = 0; free(runtimeStrings); runtimeStrings = 0; delete [] runtimeLookups; @@ -221,8 +221,8 @@ QString Binding::valueAsString(const Unit *unit) const // This code must match that in the qsTr() implementation const QString &path = unit->stringAt(unit->sourceFileIndex); int lastSlash = path.lastIndexOf(QLatin1Char('/')); - QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) : - QString(); + QStringRef context = (lastSlash > -1) ? path.midRef(lastSlash + 1, path.length() - lastSlash - 5) + : QStringRef(); QByteArray contextUtf8 = context.toUtf8(); QByteArray comment = unit->stringAt(value.translationData.commentIndex).toUtf8(); QByteArray text = unit->stringAt(stringIndex).toUtf8(); diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 8990db075d..3c2d895bff 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -351,22 +351,42 @@ struct Property enum Type { Var = 0, Variant, Int, Bool, Real, String, Url, Color, Font, Time, Date, DateTime, Rect, Point, Size, Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion, - Alias, Custom, CustomList }; + Custom, CustomList }; enum Flags { IsReadOnly = 0x1 }; quint32 nameIndex; - quint32 type; + quint32 type : 31; + quint32 flags : 1; // readonly + quint32 customTypeNameIndex; // If type >= Custom + Location location; +}; + +struct Alias { + enum Flags { + IsReadOnly = 0x1, + Resolved = 0x2, + AliasPointsToPointerObject = 0x4 + }; + quint32 nameIndex : 29; + quint32 flags : 3; union { - quint32 customTypeNameIndex; // If type >= Custom - quint32 aliasIdValueIndex; // If type == Alias + quint32 idIndex; // string index + quint32 targetObjectId; // object id index (in QQmlContextData::idValues) + }; + union { + quint32 propertyNameIndex; // string index + qint32 encodedMetaPropertyIndex; }; - quint32 aliasPropertyValueIndex; - quint32 flags; // readonly Location location; - Location aliasLocation; // If type == Alias + Location referenceLocation; + + bool isObjectAlias() const { + Q_ASSERT(flags & Resolved); + return encodedMetaPropertyIndex == -1; + } }; struct Object @@ -376,11 +396,14 @@ struct Object // it will be the name of the attached type. quint32 inheritedTypeNameIndex; quint32 idIndex; - qint32 indexOfDefaultProperty; // -1 means no default property declared in this object + qint32 indexOfDefaultPropertyOrAlias : 31; // -1 means no default property declared in this object + quint32 defaultPropertyIsAlias : 1; quint32 nFunctions; quint32 offsetToFunctions; quint32 nProperties; quint32 offsetToProperties; + quint32 nAliases; + quint32 offsetToAliases; quint32 nSignals; quint32 offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects quint32 nBindings; @@ -392,11 +415,12 @@ struct Object // Signal[] // Binding[] - static int calculateSizeExcludingSignals(int nFunctions, int nProperties, int nSignals, int nBindings) + static int calculateSizeExcludingSignals(int nFunctions, int nProperties, int nAliases, int nSignals, int nBindings) { return ( sizeof(Object) + nFunctions * sizeof(quint32) + nProperties * sizeof(Property) + + nAliases * sizeof(Alias) + nSignals * sizeof(quint32) + nBindings * sizeof(Binding) + 0x7 @@ -413,6 +437,11 @@ struct Object return reinterpret_cast<const Property*>(reinterpret_cast<const char *>(this) + offsetToProperties); } + const Alias *aliasTable() const + { + return reinterpret_cast<const Alias*>(reinterpret_cast<const char *>(this) + offsetToAliases); + } + const Binding *bindingTable() const { return reinterpret_cast<const Binding*>(reinterpret_cast<const char *>(this) + offsetToBindings); diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h index 86f812bc41..e608c08591 100644 --- a/src/qml/compiler/qv4ssa_p.h +++ b/src/qml/compiler/qv4ssa_p.h @@ -135,7 +135,7 @@ public: // Validate the new range if (_end != InvalidPosition) { Q_ASSERT(!_ranges.isEmpty()); - foreach (const Range &range, _ranges) { + for (const Range &range : qAsConst(_ranges)) { Q_ASSERT(range.start >= 0); Q_ASSERT(range.end >= 0); Q_ASSERT(range.start <= range.end); diff --git a/src/qml/debugger/qqmlprofiler.cpp b/src/qml/debugger/qqmlprofiler.cpp index 8d60325a19..629d5cb7b8 100644 --- a/src/qml/debugger/qqmlprofiler.cpp +++ b/src/qml/debugger/qqmlprofiler.cpp @@ -45,7 +45,9 @@ QT_BEGIN_NAMESPACE QQmlProfiler::QQmlProfiler() : featuresEnabled(0) { static int metatype = qRegisterMetaType<QVector<QQmlProfilerData> >(); + static int metatype2 = qRegisterMetaType<QQmlProfiler::LocationHash> (); Q_UNUSED(metatype); + Q_UNUSED(metatype2); m_timer.start(); } @@ -62,8 +64,18 @@ void QQmlProfiler::stopProfiling() void QQmlProfiler::reportData() { - emit dataReady(m_data); - m_data.clear(); + LocationHash resolved; + resolved.reserve(m_locations.size()); + for (auto it = m_locations.constBegin(), end = m_locations.constEnd(); it != end; ++it) + resolved.insert(it.key(), it.value()); + + // This unrefs all the objects. We have to make sure we do this in the GUI thread. Also, it's + // a good idea to release the memory before creating the packets to be sent. + m_locations.clear(); + + QVector<QQmlProfilerData> data; + data.swap(m_data); + emit dataReady(data, resolved); } QT_END_NAMESPACE diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h index 24001159f3..1380599fb7 100644 --- a/src/qml/debugger/qqmlprofiler_p.h +++ b/src/qml/debugger/qqmlprofiler_p.h @@ -54,6 +54,8 @@ #include <private/qv4function_p.h> #include <private/qqmlboundsignal_p.h> #include <private/qfinitestack_p.h> +#include <private/qqmlbinding_p.h> +#include <private/qqmlcompiler_p.h> #include "qqmlprofilerdefinitions_p.h" #include "qqmlabstractprofileradapter_p.h" @@ -77,40 +79,18 @@ QT_BEGIN_NAMESPACE // independently when converting to QByteArrays. Thus you can only pack // messages if their data doesn't overlap. It's up to you to figure that // out. -struct Q_AUTOTEST_EXPORT QQmlProfilerData +struct Q_AUTOTEST_EXPORT QQmlProfilerData : public QQmlProfilerDefinitions { - QQmlProfilerData() {} - - QQmlProfilerData(qint64 time, int messageType, int detailType, const QUrl &url, - int x = 0, int y = 0) : - time(time), messageType(messageType), detailType(detailType), detailUrl(url), - x(x), y(y) {} - - QQmlProfilerData(qint64 time, int messageType, int detailType, const QString &str, - int x = 0, int y = 0) : - time(time), messageType(messageType), detailType(detailType),detailString(str), - x(x), y(y) {} - - QQmlProfilerData(qint64 time, int messageType, int detailType, const QString &str, - const QUrl &url, int x = 0, int y = 0) : - time(time), messageType(messageType), detailType(detailType), detailString(str), - detailUrl(url), x(x), y(y) {} - - - QQmlProfilerData(qint64 time, int messageType, int detailType) : - time(time), messageType(messageType), detailType(detailType) {} - + QQmlProfilerData(qint64 time = -1, int messageType = -1, + RangeType detailType = MaximumRangeType, quintptr locationId = 0) : + time(time), locationId(locationId), messageType(messageType), detailType(detailType) + {} qint64 time; - int messageType; //bit field of QQmlProfilerService::Message - int detailType; + quintptr locationId; - // RangeData prefers detailString; RangeLocation prefers detailUrl. - QString detailString; //used by RangeData and possibly by RangeLocation - QUrl detailUrl; //used by RangeLocation and possibly by RangeData - - int x; //used by RangeLocation - int y; //used by RangeLocation + int messageType; //bit field of QQmlProfilerService::Message + RangeType detailType; }; Q_DECLARE_TYPEINFO(QQmlProfilerData, Q_MOVABLE_TYPE); @@ -118,58 +98,166 @@ Q_DECLARE_TYPEINFO(QQmlProfilerData, Q_MOVABLE_TYPE); class QQmlProfiler : public QObject, public QQmlProfilerDefinitions { Q_OBJECT public: - void startBinding(const QQmlSourceLocation &location) + + class BindingRefCount : public QQmlRefCount { + public: + BindingRefCount(QQmlBinding *binding): + m_binding(binding) + { + m_binding->ref.ref(); + } + + BindingRefCount(const BindingRefCount &other) : + QQmlRefCount(other), m_binding(other.m_binding) + { + m_binding->ref.ref(); + } + + BindingRefCount &operator=(const BindingRefCount &other) + { + if (this != &other) { + QQmlRefCount::operator=(other); + other.m_binding->ref.ref(); + if (!m_binding->ref.deref()) + delete m_binding; + m_binding = other.m_binding; + } + return *this; + } + + ~BindingRefCount() + { + if (!m_binding->ref.deref()) + delete m_binding; + } + + private: + QQmlBinding *m_binding; + }; + + struct Location { + Location(const QQmlSourceLocation &location = QQmlSourceLocation(), + const QUrl &url = QUrl()) : + location(location), url(url) {} + QQmlSourceLocation location; + QUrl url; + }; + + // Unfortunately we have to resolve the locations right away because the QML context might not + // be available anymore when we send the data. + struct RefLocation : public Location { + RefLocation() : Location(), locationType(MaximumRangeType), ref(nullptr) + {} + + RefLocation(QQmlBinding *binding, QV4::FunctionObject *function) : + Location(function->sourceLocation()), locationType(Binding), + ref(new BindingRefCount(binding), QQmlRefPointer<QQmlRefCount>::Adopt) + {} + + RefLocation(QQmlCompiledData *ref, const QUrl &url, const QV4::CompiledData::Object *obj, + const QString &type) : + Location(QQmlSourceLocation(type, obj->location.line, obj->location.column), url), + locationType(Creating), ref(ref) + {} + + RefLocation(QQmlBoundSignalExpression *ref) : + Location(ref->sourceLocation()), locationType(HandlingSignal), ref(ref) + {} + + RefLocation(QQmlDataBlob *ref) : + Location(QQmlSourceLocation(), ref->url()), locationType(Compiling), ref(ref) + {} + + bool isValid() const + { + return locationType != MaximumRangeType; + } + + RangeType locationType; + QQmlRefPointer<QQmlRefCount> ref; + }; + + typedef QHash<quintptr, Location> LocationHash; + + void startBinding(QQmlBinding *binding, QV4::FunctionObject *function) { + quintptr locationId(id(binding)); m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), - (1 << RangeStart | 1 << RangeLocation), 1 << Binding, - location.sourceFile, qmlSourceCoordinate(location.line), qmlSourceCoordinate(location.column))); + (1 << RangeStart | 1 << RangeLocation), Binding, + locationId)); + + RefLocation &location = m_locations[locationId]; + if (!location.isValid()) + location = RefLocation(binding, function); } // Have toByteArrays() construct another RangeData event from the same QString later. // This is somewhat pointless but important for backwards compatibility. - void startCompiling(const QUrl &url) + void startCompiling(QQmlDataBlob *blob) { + quintptr locationId(id(blob)); m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), (1 << RangeStart | 1 << RangeLocation | 1 << RangeData), - 1 << Compiling, url, 1, 1)); + Compiling, locationId)); + + RefLocation &location = m_locations[locationId]; + if (!location.isValid()) + location = RefLocation(blob); } - void startHandlingSignal(const QQmlSourceLocation &location) + void startHandlingSignal(QQmlBoundSignalExpression *expression) { + quintptr locationId(id(expression)); m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), - (1 << RangeStart | 1 << RangeLocation), 1 << HandlingSignal, - location.sourceFile, location.line, location.column)); + (1 << RangeStart | 1 << RangeLocation), HandlingSignal, + locationId)); + + RefLocation &location = m_locations[locationId]; + if (!location.isValid()) + location = RefLocation(expression); } void startCreating() { - m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), 1 << RangeStart, 1 << Creating)); + m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), 1 << RangeStart, Creating)); } - void startCreating(const QString &typeName, const QUrl &fileName, int line, int column) + void startCreating(const QV4::CompiledData::Object *obj) { m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), (1 << RangeStart | 1 << RangeLocation | 1 << RangeData), - 1 << Creating, typeName, fileName, line, column)); + Creating, id(obj))); } - void updateCreating(const QString &typeName, const QUrl &fileName, int line, int column) + void updateCreating(const QV4::CompiledData::Object *obj, QQmlCompiledData *ref, + const QUrl &url, const QString &type) { + quintptr locationId(id(obj)); m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), (1 << RangeLocation | 1 << RangeData), - 1 << Creating, typeName, fileName, line, column)); + Creating, locationId)); + + RefLocation &location = m_locations[locationId]; + if (!location.isValid()) + location = RefLocation(ref, url, obj, type); } template<RangeType Range> void endRange() { - m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), 1 << RangeEnd, 1 << Range)); + m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), 1 << RangeEnd, Range)); } QQmlProfiler(); quint64 featuresEnabled; + template<typename Object> + static quintptr id(const Object *pointer) + { + return reinterpret_cast<quintptr>(pointer); + } + public slots: void startProfiling(quint64 features); void stopProfiling(); @@ -177,10 +265,11 @@ public slots: void setTimer(const QElapsedTimer &timer) { m_timer = timer; } signals: - void dataReady(const QVector<QQmlProfilerData> &); + void dataReady(const QVector<QQmlProfilerData> &, const QQmlProfiler::LocationHash &); protected: QElapsedTimer m_timer; + QHash<quintptr, RefLocation> m_locations; QVector<QQmlProfilerData> m_data; }; @@ -194,11 +283,12 @@ struct QQmlProfilerHelper : public QQmlProfilerDefinitions { }; struct QQmlBindingProfiler : public QQmlProfilerHelper { - QQmlBindingProfiler(QQmlProfiler *profiler, const QV4::FunctionObject *function) : + QQmlBindingProfiler(QQmlProfiler *profiler, QQmlBinding *binding, + QV4::FunctionObject *function) : QQmlProfilerHelper(profiler) { Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileBinding, profiler, - startBinding(function->sourceLocation())); + startBinding(binding, function)); } ~QQmlBindingProfiler() @@ -213,7 +303,7 @@ struct QQmlHandlingSignalProfiler : public QQmlProfilerHelper { QQmlProfilerHelper(profiler) { Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileHandlingSignal, profiler, - startHandlingSignal(expression->sourceLocation())); + startHandlingSignal(expression)); } ~QQmlHandlingSignalProfiler() @@ -224,10 +314,10 @@ struct QQmlHandlingSignalProfiler : public QQmlProfilerHelper { }; struct QQmlCompilingProfiler : public QQmlProfilerHelper { - QQmlCompilingProfiler(QQmlProfiler *profiler, const QUrl &url) : + QQmlCompilingProfiler(QQmlProfiler *profiler, QQmlDataBlob *blob) : QQmlProfilerHelper(profiler) { - Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCompiling, profiler, startCompiling(url)); + Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCompiling, profiler, startCompiling(blob)); } ~QQmlCompilingProfiler() @@ -239,14 +329,6 @@ struct QQmlCompilingProfiler : public QQmlProfilerHelper { struct QQmlVmeProfiler : public QQmlProfilerDefinitions { public: - struct Data { - Data() : m_line(0), m_column(0) {} - QUrl m_url; - int m_line; - int m_column; - QString m_typeName; - }; - QQmlVmeProfiler() : profiler(0) {} void init(QQmlProfiler *p, int maxDepth) @@ -255,30 +337,30 @@ public: ranges.allocate(maxDepth); } - Data pop() + const QV4::CompiledData::Object *pop() { if (ranges.count() > 0) return ranges.pop(); else - return Data(); + return nullptr; } - void push(const Data &data) + void push(const QV4::CompiledData::Object *object) { if (ranges.capacity() > ranges.count()) - ranges.push(data); + ranges.push(object); } QQmlProfiler *profiler; private: - QFiniteStack<Data> ranges; + QFiniteStack<const QV4::CompiledData::Object *> ranges; }; #define Q_QML_OC_PROFILE(member, Code)\ Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, member.profiler, Code) -class QQmlObjectCreationProfiler : public QQmlVmeProfiler::Data { +class QQmlObjectCreationProfiler { public: QQmlObjectCreationProfiler(QQmlProfiler *profiler) : profiler(profiler) @@ -291,13 +373,10 @@ public: Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCreating, profiler, endRange<QQmlProfilerDefinitions::Creating>()); } - void update(const QString &typeName, const QUrl &url, int line, int column) + void update(QQmlCompiledData *ref, const QV4::CompiledData::Object *obj, + const QString &typeName, const QUrl &url) { - profiler->updateCreating(typeName, url, line, column); - m_typeName = typeName; - m_url = url; - m_line = line; - m_column = column; + profiler->updateCreating(obj, ref, url, typeName); } private: @@ -310,8 +389,7 @@ public: profiler(parent->profiler) { Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, profiler, { - QQmlVmeProfiler::Data data = parent->pop(); - profiler->startCreating(data.m_typeName, data.m_url, data.m_line, data.m_column); + profiler->startCreating(parent->pop()); }); } @@ -326,5 +404,6 @@ private: QT_END_NAMESPACE Q_DECLARE_METATYPE(QVector<QQmlProfilerData>) +Q_DECLARE_METATYPE(QQmlProfiler::LocationHash) #endif // QQMLPROFILER_P_H diff --git a/src/qml/doc/src/cppintegration/data.qdoc b/src/qml/doc/src/cppintegration/data.qdoc index e153ca3d8b..0d875bd10f 100644 --- a/src/qml/doc/src/cppintegration/data.qdoc +++ b/src/qml/doc/src/cppintegration/data.qdoc @@ -112,7 +112,7 @@ when passed from C++ to QML and vice-versa: \li QVector2D, QVector3D, QVector4D \li \l vector2d, \l vector3d, \l vector4d \row - \li Enums declared with Q_ENUMS() + \li Enums declared with Q_ENUM() or Q_ENUMS() \li \l enumeration \endtable @@ -261,6 +261,9 @@ In particular, QML currently supports: \li \c {QList<bool>} \li \c {QList<QString>} and \c{QStringList} \li \c {QList<QUrl>} + \li \c {QVector<int>} + \li \c {QVector<qreal>} + \li \c {QVector<bool>} \endlist These sequence types are implemented directly in terms of the underlying C++ @@ -303,6 +306,9 @@ The default-constructed values for each sequence type are as follows: \row \li QList<bool> \li boolean value \c {false} \row \li QList<QString> and QStringList \li empty QString \row \li QList<QUrl> \li empty QUrl +\row \li QVector<int> \li integer value 0 +\row \li QVector<qreal> \li real value 0.0 +\row \li QVector<bool> \li boolean value \c {false} \endtable If you wish to remove elements from a sequence rather than simply replace @@ -341,7 +347,7 @@ properties: \section1 Enumeration Types To use a custom enumeration as a data type, its class must be registered and -the enumeration must also be declared with Q_ENUMS() to register it with Qt's +the enumeration must also be declared with Q_ENUM() to register it with Qt's meta object system. For example, the \c Message class below has a \c Status enum: @@ -349,7 +355,6 @@ enum: class Message : public QObject { Q_OBJECT - Q_ENUMS(Status) Q_PROPERTY(Status status READ status NOTIFY statusChanged) public: enum Status { @@ -357,6 +362,7 @@ enum: Loading, Error }; + Q_ENUM(Status) Status status() const; signals: void statusChanged(); diff --git a/src/qml/doc/src/cppintegration/extending-tutorial.qdoc b/src/qml/doc/src/cppintegration/extending-tutorial.qdoc index d862b50fcb..c0cfc3e1aa 100644 --- a/src/qml/doc/src/cppintegration/extending-tutorial.qdoc +++ b/src/qml/doc/src/cppintegration/extending-tutorial.qdoc @@ -386,12 +386,26 @@ directory. \quotefile tutorials/extending-qml/chapter6-plugins/import/import.pro -In this example, the \c Charts directory is located at the same level as the application -that uses our new import module. This way, the QML engine will find our module -as the default search path for QML imports includes the directory of the application -executable. Alternatively, we could control what directories the \l {QML Import Path} -{QML import path} contains, useful if there are multiple QML applications using the -same QML imports. +When building this example on Windows or Linux, the \c Charts directory will be +located at the same level as the application that uses our new import module. +This way, the QML engine will find our module as the default search path for QML +imports includes the directory of the application executable. On OS X, the +plugin binary is copied to \c Contents/PlugIns in the the application bundle; +this path is set in \l {tutorials/extending-qml/chapter6-plugins/app.pro} +{chapter6-plugins/app.pro}: + +\quotefromfile tutorials/extending-qml/chapter6-plugins/app.pro +\skipto osx +\printuntil } + +To account for this, we also need to add this location as a +\l {QML Import Path}{QML import path} in \c main.cpp: + +\snippet tutorials/extending-qml/chapter6-plugins/main.cpp 0 +\dots + +Defining custom import paths is useful also when there are multiple +applications using the same QML imports. The \c .pro file also contains additional magic to ensure that the \l {Module Definition qmldir Files}{module definition qmldir file} is always copied diff --git a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc index 04d769e4dc..04d0d0ed2e 100644 --- a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc +++ b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc @@ -508,7 +508,7 @@ built-in \l {Rectangle::color} property: Any object that use this type and refer to its \c color property will be referring to the alias rather than the ordinary \l {Rectangle::color} property. -Internally, however, the red can correctly set its \c color +Internally, however, the rectangle can correctly set its \c color property and refer to the actual defined property rather than the alias. diff --git a/src/qml/jit/qv4targetplatform_p.h b/src/qml/jit/qv4targetplatform_p.h index 80a18a7f5b..54b17c4f07 100644 --- a/src/qml/jit/qv4targetplatform_p.h +++ b/src/qml/jit/qv4targetplatform_p.h @@ -134,7 +134,8 @@ public: static int ebxIdx = -1; if (ebxIdx == -1) { int calleeSaves = 0; - foreach (const RegisterInfo &info, getRegisterInfo()) { + const auto infos = getRegisterInfo(); + for (const RegisterInfo &info : infos) { if (info.reg<JSC::X86Registers::RegisterID>() == JSC::X86Registers::ebx) { ebxIdx = calleeSaves; break; diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp index 424d5548a1..257dd357fd 100644 --- a/src/qml/jsapi/qjsengine.cpp +++ b/src/qml/jsapi/qjsengine.cpp @@ -247,6 +247,11 @@ Q_DECLARE_METATYPE(QList<int>) QT_BEGIN_NAMESPACE +static void checkForApplicationInstance() +{ + if (!QCoreApplication::instance()) + qFatal("QJSEngine: Must construct a QCoreApplication before a QJSEngine"); +} /*! Constructs a QJSEngine object. @@ -270,6 +275,8 @@ QJSEngine::QJSEngine(QObject *parent) : QObject(*new QJSEnginePrivate, parent) , d(new QV8Engine(this)) { + checkForApplicationInstance(); + QJSEnginePrivate::addToDebugServer(this); } @@ -280,6 +287,7 @@ QJSEngine::QJSEngine(QJSEnginePrivate &dd, QObject *parent) : QObject(dd, parent) , d(new QV8Engine(this)) { + checkForApplicationInstance(); } /*! diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp index 73aa7047b8..4c4639c94f 100644 --- a/src/qml/jsruntime/qv4arraydata.cpp +++ b/src/qml/jsruntime/qv4arraydata.cpp @@ -287,7 +287,13 @@ void SimpleArrayData::push_front(Object *o, const Value *values, uint n) Q_ASSERT(o->d()->arrayData->type == Heap::ArrayData::Simple); dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); } - dd->offset = (dd->offset - n) % dd->alloc; + if (n <= dd->offset) { + dd->offset -= n; // there is enough space left in front + } else { + // we need to wrap around, so: + dd->offset = dd->alloc - // start at the back, but subtract: + (n - dd->offset); // the number of items we can put in the free space at the start of the allocated array + } dd->len += n; for (uint i = 0; i < n; ++i) dd->data(i) = values[i].asReturnedValue(); diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index 5783e8fa2b..0cd72d6811 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -338,7 +338,7 @@ static inline double currentTime() static inline double TimeClip(double t) { - if (! qIsFinite(t) || fabs(t) > 8.64e15) + if (! qt_is_finite(t) || fabs(t) > 8.64e15) return qt_qnan(); return Primitive::toInteger(t); } diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp index 9f1e6b613b..2db04bbfda 100644 --- a/src/qml/jsruntime/qv4errorobject.cpp +++ b/src/qml/jsruntime/qv4errorobject.cpp @@ -160,13 +160,9 @@ ReturnedValue ErrorObject::method_get_stack(CallContext *ctx) if (i > 0) trace += QLatin1Char('\n'); const StackFrame &frame = This->d()->stackTrace[i]; - trace += frame.function; - trace += QLatin1Char('@'); - trace += frame.source; - if (frame.line >= 0) { - trace += QLatin1Char(':'); - trace += QString::number(frame.line); - } + trace += frame.function + QLatin1Char('@') + frame.source; + if (frame.line >= 0) + trace += QLatin1Char(':') + QString::number(frame.line); } This->d()->stack = ctx->d()->engine->newString(trace); } diff --git a/src/qml/jsruntime/qv4identifier.cpp b/src/qml/jsruntime/qv4identifier.cpp index c8d66b1254..626648067f 100644 --- a/src/qml/jsruntime/qv4identifier.cpp +++ b/src/qml/jsruntime/qv4identifier.cpp @@ -131,7 +131,7 @@ const IdentifierHashEntry *IdentifierHashBase::lookup(const QString &str) const return 0; Q_ASSERT(d->entries); - uint hash = String::createHashValue(str.constData(), str.length()); + uint hash = String::createHashValue(str.constData(), str.length(), Q_NULLPTR); uint idx = hash % d->alloc; while (1) { if (!d->entries[idx].identifier) diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp index 5adb17b4ea..3def6defbf 100644 --- a/src/qml/jsruntime/qv4identifiertable.cpp +++ b/src/qml/jsruntime/qv4identifiertable.cpp @@ -118,7 +118,8 @@ void IdentifierTable::addEntry(Heap::String *str) Heap::String *IdentifierTable::insertString(const QString &s) { - uint hash = String::createHashValue(s.constData(), s.length()); + uint subtype; + uint hash = String::createHashValue(s.constData(), s.length(), &subtype); uint idx = hash % alloc; while (Heap::String *e = entries[idx]) { if (e->stringHash == hash && e->toQString() == s) @@ -128,6 +129,8 @@ Heap::String *IdentifierTable::insertString(const QString &s) } Heap::String *str = engine->newString(s); + str->stringHash = hash; + str->subtype = subtype; addEntry(str); return str; } @@ -178,7 +181,8 @@ Identifier *IdentifierTable::identifier(const QString &s) Identifier *IdentifierTable::identifier(const char *s, int len) { - uint hash = String::createHashValue(s, len); + uint subtype; + uint hash = String::createHashValue(s, len, &subtype); if (hash == UINT_MAX) return identifier(QString::fromUtf8(s, len)); @@ -192,6 +196,8 @@ Identifier *IdentifierTable::identifier(const char *s, int len) } Heap::String *str = engine->newString(QString::fromLatin1(s, len)); + str->stringHash = hash; + str->subtype = subtype; addEntry(str); return str->identifier; } diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index a5405dad0d..9660a5e76d 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -429,11 +429,13 @@ InternalClass *InternalClass::propertiesFrozen() const void InternalClass::destroy() { - QList<InternalClass *> destroyStack; - destroyStack.append(this); + std::vector<InternalClass *> destroyStack; + destroyStack.reserve(64); + destroyStack.push_back(this); - while (!destroyStack.isEmpty()) { - InternalClass *next = destroyStack.takeLast(); + while (!destroyStack.empty()) { + InternalClass *next = destroyStack.back(); + destroyStack.pop_back(); if (!next->engine) continue; next->engine = 0; @@ -441,13 +443,13 @@ void InternalClass::destroy() next->nameMap.~SharedInternalClassData<Identifier *>(); next->propertyData.~SharedInternalClassData<PropertyAttributes>(); if (next->m_sealed) - destroyStack.append(next->m_sealed); + destroyStack.push_back(next->m_sealed); if (next->m_frozen) - destroyStack.append(next->m_frozen); + destroyStack.push_back(next->m_frozen); for (size_t i = 0; i < next->transitions.size(); ++i) { Q_ASSERT(next->transitions.at(i).lookup); - destroyStack.append(next->transitions.at(i).lookup); + destroyStack.push_back(next->transitions.at(i).lookup); } next->transitions.~vector<Transition>(); diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index a211d46153..0ae7c33dea 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -590,8 +590,7 @@ bool JsonParser::parseString(QString *string) return false; } if (QChar::requiresSurrogates(ch)) { - *string += QChar(QChar::highSurrogate(ch)); - *string += QChar(QChar::lowSurrogate(ch)); + *string += QChar(QChar::highSurrogate(ch)) + QChar(QChar::lowSurrogate(ch)); } else { *string += QChar(ch); } @@ -672,8 +671,8 @@ static QString quote(const QString &str) default: if (c.unicode() <= 0x1f) { product += QStringLiteral("\\u00"); - product += c.unicode() > 0xf ? QLatin1Char('1') : QLatin1Char('0'); - product += QLatin1Char("0123456789abcdef"[c.unicode() & 0xf]); + product += (c.unicode() > 0xf ? QLatin1Char('1') : QLatin1Char('0')) + + QLatin1Char("0123456789abcdef"[c.unicode() & 0xf]); } else { product += c; } diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 0727f35edd..ff3208485e 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -753,9 +753,8 @@ void Object::internalPut(String *name, const Value &value) reject: if (engine()->current->strictMode) { - QString message = QStringLiteral("Cannot assign to read-only property \""); - message += name->toQString(); - message += QLatin1Char('\"'); + QString message = QStringLiteral("Cannot assign to read-only property \"") + + name->toQString() + QLatin1Char('\"'); engine()->throwTypeError(message); } } diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp index c0a4129d9d..72475c5416 100644 --- a/src/qml/jsruntime/qv4profiling.cpp +++ b/src/qml/jsruntime/qv4profiling.cpp @@ -46,26 +46,32 @@ QT_BEGIN_NAMESPACE namespace QV4 { namespace Profiling { -FunctionCallProperties FunctionCall::resolve() const +FunctionLocation FunctionCall::resolveLocation() const +{ + return FunctionLocation(m_function->name()->toQString(), + m_function->compilationUnit->fileName(), + m_function->compiledFunction->location.line, + m_function->compiledFunction->location.column); +} + +FunctionCallProperties FunctionCall::properties() const { FunctionCallProperties props = { m_start, m_end, - m_function->name()->toQString(), - m_function->compilationUnit->fileName(), - m_function->compiledFunction->location.line, - m_function->compiledFunction->location.column + reinterpret_cast<quintptr>(m_function) }; return props; } - Profiler::Profiler(QV4::ExecutionEngine *engine) : featuresEnabled(0), m_engine(engine) { - static int meta = qRegisterMetaType<QVector<QV4::Profiling::FunctionCallProperties> >(); - static int meta2 = qRegisterMetaType<QVector<QV4::Profiling::MemoryAllocationProperties> >(); - Q_UNUSED(meta); - Q_UNUSED(meta2); + static const int metatypes[] = { + qRegisterMetaType<QVector<QV4::Profiling::FunctionCallProperties> >(), + qRegisterMetaType<QVector<QV4::Profiling::MemoryAllocationProperties> >(), + qRegisterMetaType<FunctionLocationHash>() + }; + Q_UNUSED(metatypes); m_timer.start(); } @@ -85,13 +91,18 @@ bool operator<(const FunctionCall &call1, const FunctionCall &call2) void Profiler::reportData() { std::sort(m_data.begin(), m_data.end()); - QVector<FunctionCallProperties> resolved; - resolved.reserve(m_data.size()); + QVector<FunctionCallProperties> properties; + FunctionLocationHash locations; + properties.reserve(m_data.size()); - foreach (const FunctionCall &call, m_data) - resolved.append(call.resolve()); + foreach (const FunctionCall &call, m_data) { + properties.append(call.properties()); + FunctionLocation &location = locations[properties.constLast().id]; + if (!location.isValid()) + location = call.resolveLocation(); + } - emit dataReady(resolved, m_memory_data); + emit dataReady(locations, properties, m_memory_data); m_data.clear(); m_memory_data.clear(); } diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h index 25ef8223bf..bb128b7cf3 100644 --- a/src/qml/jsruntime/qv4profiling_p.h +++ b/src/qml/jsruntime/qv4profiling_p.h @@ -77,12 +77,28 @@ enum MemoryType { struct FunctionCallProperties { qint64 start; qint64 end; + quintptr id; +}; + +struct FunctionLocation { + FunctionLocation(const QString &name = QString(), const QString &file = QString(), + int line = -1, int column = -1) : + name(name), file(file), line(line), column(column) + {} + + bool isValid() + { + return !name.isEmpty(); + } + QString name; QString file; int line; int column; }; +typedef QHash<quintptr, QV4::Profiling::FunctionLocation> FunctionLocationHash; + struct MemoryAllocationProperties { qint64 timestamp; qint64 size; @@ -118,7 +134,8 @@ public: return *this; } - FunctionCallProperties resolve() const; + FunctionLocation resolveLocation() const; + FunctionCallProperties properties() const; private: friend bool operator<(const FunctionCall &call1, const FunctionCall &call2); @@ -173,7 +190,8 @@ public slots: void setTimer(const QElapsedTimer &timer) { m_timer = timer; } signals: - void dataReady(const QVector<QV4::Profiling::FunctionCallProperties> &, + void dataReady(const QV4::Profiling::FunctionLocationHash &, + const QVector<QV4::Profiling::FunctionCallProperties> &, const QVector<QV4::Profiling::MemoryAllocationProperties> &); private: @@ -218,8 +236,10 @@ public: Q_DECLARE_TYPEINFO(QV4::Profiling::MemoryAllocationProperties, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCallProperties, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCall, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionLocation, Q_MOVABLE_TYPE); QT_END_NAMESPACE +Q_DECLARE_METATYPE(QV4::Profiling::FunctionLocationHash) Q_DECLARE_METATYPE(QVector<QV4::Profiling::FunctionCallProperties>) Q_DECLARE_METATYPE(QVector<QV4::Profiling::MemoryAllocationProperties>) diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index fca218d9d0..35fcd00eb7 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -1285,6 +1285,8 @@ static int MatchScore(const QV4::Value &actual, int conversionType) return 10; } else if (conversionType == QMetaType::QJsonObject) { return 5; + } else if (conversionType == qMetaTypeId<QJSValue>()) { + return 0; } else { return 10; } @@ -1768,17 +1770,13 @@ QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx) co QString result; if (const QMetaObject *metaObject = d()->metaObject()) { - result += QString::fromUtf8(metaObject->className()); - result += QLatin1String("(0x"); - result += QString::number((quintptr)d()->object.data(),16); + result += QString::fromUtf8(metaObject->className()) + + QLatin1String("(0x") + QString::number((quintptr)d()->object.data(),16); if (d()->object) { QString objectName = d()->object->objectName(); - if (!objectName.isEmpty()) { - result += QLatin1String(", \""); - result += objectName; - result += QLatin1Char('\"'); - } + if (!objectName.isEmpty()) + result += QLatin1String(", \"") + objectName + QLatin1Char('\"'); } result += QLatin1Char(')'); diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index 71e2bd1a06..05752dc6dc 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -185,8 +185,7 @@ QRegExp RegExpObject::toQRegExp() const QString RegExpObject::toString() const { - QString result = QLatin1Char('/') + source(); - result += QLatin1Char('/'); + QString result = QLatin1Char('/') + source() + QLatin1Char('/'); if (global()) result += QLatin1Char('g'); if (value()->ignoreCase) diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index a974909798..b7543692d5 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -984,10 +984,9 @@ ReturnedValue Runtime::method_callQmlScopeObjectProperty(ExecutionEngine *engine Scope scope(engine); ScopedFunctionObject o(scope, method_getQmlScopeObjectProperty(engine, callData->thisObject, propertyIndex)); if (!o) { - QString error = QStringLiteral("Property '%1' of object %2 is not a function").arg(propertyIndex).arg(callData->thisObject.toQStringNoThrow()); + QString error = QStringLiteral("Property '%1' of scope object is not a function").arg(propertyIndex); return engine->throwTypeError(error); } - return o->call(callData); } @@ -996,7 +995,7 @@ ReturnedValue Runtime::method_callQmlContextObjectProperty(ExecutionEngine *engi Scope scope(engine); ScopedFunctionObject o(scope, method_getQmlContextObjectProperty(engine, callData->thisObject, propertyIndex)); if (!o) { - QString error = QStringLiteral("Property '%1' of object %2 is not a function").arg(propertyIndex).arg(callData->thisObject.toQStringNoThrow()); + QString error = QStringLiteral("Property '%1' of context object is not a function").arg(propertyIndex); return engine->throwTypeError(error); } @@ -1623,6 +1622,351 @@ void Runtime::method_convertThisToObject(ExecutionEngine *engine) } } +ReturnedValue Runtime::method_uPlus(const Value &value) +{ + TRACE1(value); + + if (value.isNumber()) + return value.asReturnedValue(); + if (value.integerCompatible()) + return Encode(value.int_32()); + + double n = value.toNumberImpl(); + return Encode(n); +} + +ReturnedValue Runtime::method_uMinus(const Value &value) +{ + TRACE1(value); + + // +0 != -0, so we need to convert to double when negating 0 + if (value.isInteger() && value.integerValue()) + return Encode(-value.integerValue()); + else { + double n = RuntimeHelpers::toNumber(value); + return Encode(-n); + } +} + +ReturnedValue Runtime::method_complement(const Value &value) +{ + TRACE1(value); + + int n = value.toInt32(); + return Encode((int)~n); +} + +ReturnedValue Runtime::method_uNot(const Value &value) +{ + TRACE1(value); + + bool b = value.toBoolean(); + return Encode(!b); +} + +// binary operators +ReturnedValue Runtime::method_bitOr(const Value &left, const Value &right) +{ + TRACE2(left, right); + + int lval = left.toInt32(); + int rval = right.toInt32(); + return Encode(lval | rval); +} + +ReturnedValue Runtime::method_bitXor(const Value &left, const Value &right) +{ + TRACE2(left, right); + + int lval = left.toInt32(); + int rval = right.toInt32(); + return Encode(lval ^ rval); +} + +ReturnedValue Runtime::method_bitAnd(const Value &left, const Value &right) +{ + TRACE2(left, right); + + int lval = left.toInt32(); + int rval = right.toInt32(); + return Encode(lval & rval); +} + +#ifndef V4_BOOTSTRAP +ReturnedValue Runtime::method_add(ExecutionEngine *engine, const Value &left, const Value &right) +{ + TRACE2(left, right); + + if (Q_LIKELY(left.isInteger() && right.isInteger())) + return add_int32(left.integerValue(), right.integerValue()); + if (left.isNumber() && right.isNumber()) + return Primitive::fromDouble(left.asDouble() + right.asDouble()).asReturnedValue(); + + return RuntimeHelpers::addHelper(engine, left, right); +} +#endif // V4_BOOTSTRAP + +ReturnedValue Runtime::method_sub(const Value &left, const Value &right) +{ + TRACE2(left, right); + + if (Q_LIKELY(left.isInteger() && right.isInteger())) + return sub_int32(left.integerValue(), right.integerValue()); + + double lval = left.isNumber() ? left.asDouble() : left.toNumberImpl(); + double rval = right.isNumber() ? right.asDouble() : right.toNumberImpl(); + + return Primitive::fromDouble(lval - rval).asReturnedValue(); +} + +ReturnedValue Runtime::method_mul(const Value &left, const Value &right) +{ + TRACE2(left, right); + + if (Q_LIKELY(left.isInteger() && right.isInteger())) + return mul_int32(left.integerValue(), right.integerValue()); + + double lval = left.isNumber() ? left.asDouble() : left.toNumberImpl(); + double rval = right.isNumber() ? right.asDouble() : right.toNumberImpl(); + + return Primitive::fromDouble(lval * rval).asReturnedValue(); +} + +ReturnedValue Runtime::method_div(const Value &left, const Value &right) +{ + TRACE2(left, right); + + if (Value::integerCompatible(left, right)) { + int lval = left.integerValue(); + int rval = right.integerValue(); + if (rval != 0 && (lval % rval == 0)) + return Encode(int(lval / rval)); + else + return Encode(double(lval) / rval); + } + + double lval = left.toNumber(); + double rval = right.toNumber(); + return Primitive::fromDouble(lval / rval).asReturnedValue(); +} + +ReturnedValue Runtime::method_mod(const Value &left, const Value &right) +{ + TRACE2(left, right); + + if (Value::integerCompatible(left, right) && right.integerValue() != 0) { + int intRes = left.integerValue() % right.integerValue(); + if (intRes != 0 || left.integerValue() >= 0) + return Encode(intRes); + } + + double lval = RuntimeHelpers::toNumber(left); + double rval = RuntimeHelpers::toNumber(right); +#ifdef fmod +# undef fmod +#endif + return Primitive::fromDouble(std::fmod(lval, rval)).asReturnedValue(); +} + +ReturnedValue Runtime::method_shl(const Value &left, const Value &right) +{ + TRACE2(left, right); + + int lval = left.toInt32(); + int rval = right.toInt32() & 0x1f; + return Encode((int)(lval << rval)); +} + +ReturnedValue Runtime::method_shr(const Value &left, const Value &right) +{ + TRACE2(left, right); + + int lval = left.toInt32(); + unsigned rval = right.toUInt32() & 0x1f; + return Encode((int)(lval >> rval)); +} + +ReturnedValue Runtime::method_ushr(const Value &left, const Value &right) +{ + TRACE2(left, right); + + unsigned lval = left.toUInt32(); + unsigned rval = right.toUInt32() & 0x1f; + uint res = lval >> rval; + + return Encode(res); +} + +ReturnedValue Runtime::method_greaterThan(const Value &left, const Value &right) +{ + TRACE2(left, right); + + bool r = method_compareGreaterThan(left, right); + return Encode(r); +} + +ReturnedValue Runtime::method_lessThan(const Value &left, const Value &right) +{ + TRACE2(left, right); + + bool r = method_compareLessThan(left, right); + return Encode(r); +} + +ReturnedValue Runtime::method_greaterEqual(const Value &left, const Value &right) +{ + TRACE2(left, right); + + bool r = method_compareGreaterEqual(left, right); + return Encode(r); +} + +ReturnedValue Runtime::method_lessEqual(const Value &left, const Value &right) +{ + TRACE2(left, right); + + bool r = method_compareLessEqual(left, right); + return Encode(r); +} + +Bool Runtime::method_compareEqual(const Value &left, const Value &right) +{ + TRACE2(left, right); + + if (left.rawValue() == right.rawValue()) + // NaN != NaN + return !left.isNaN(); + + if (left.type() == right.type()) { + if (!left.isManaged()) + return false; + if (left.isString() == right.isString()) + return left.cast<Managed>()->isEqualTo(right.cast<Managed>()); + } + + return RuntimeHelpers::equalHelper(left, right); +} + +ReturnedValue Runtime::method_equal(const Value &left, const Value &right) +{ + TRACE2(left, right); + + bool r = method_compareEqual(left, right); + return Encode(r); +} + +ReturnedValue Runtime::method_notEqual(const Value &left, const Value &right) +{ + TRACE2(left, right); + + bool r = !method_compareEqual(left, right); + return Encode(r); +} + +ReturnedValue Runtime::method_strictEqual(const Value &left, const Value &right) +{ + TRACE2(left, right); + + bool r = RuntimeHelpers::strictEqual(left, right); + return Encode(r); +} + +ReturnedValue Runtime::method_strictNotEqual(const Value &left, const Value &right) +{ + TRACE2(left, right); + + bool r = ! RuntimeHelpers::strictEqual(left, right); + return Encode(r); +} + +Bool Runtime::method_compareNotEqual(const Value &left, const Value &right) +{ + TRACE2(left, right); + + return !Runtime::method_compareEqual(left, right); +} + +Bool Runtime::method_compareStrictEqual(const Value &left, const Value &right) +{ + TRACE2(left, right); + + return RuntimeHelpers::strictEqual(left, right); +} + +Bool Runtime::method_compareStrictNotEqual(const Value &left, const Value &right) +{ + TRACE2(left, right); + + return ! RuntimeHelpers::strictEqual(left, right); +} + +Bool Runtime::method_toBoolean(const Value &value) +{ + return value.toBoolean(); +} + +ReturnedValue Runtime::method_accessQmlScopeObjectQRealProperty(const Value &context, + QQmlAccessors *accessors) +{ +#ifndef V4_BOOTSTRAP + const QmlContext &c = static_cast<const QmlContext &>(context); + qreal rv = 0; + accessors->read(c.d()->qml->scopeObject, &rv); + return QV4::Encode(rv); +#else + Q_UNUSED(context); + Q_UNUSED(accessors); + return QV4::Encode::undefined(); +#endif +} + +ReturnedValue Runtime::method_accessQmlScopeObjectIntProperty(const Value &context, + QQmlAccessors *accessors) +{ +#ifndef V4_BOOTSTRAP + const QmlContext &c = static_cast<const QmlContext &>(context); + int rv = 0; + accessors->read(c.d()->qml->scopeObject, &rv); + return QV4::Encode(rv); +#else + Q_UNUSED(context); + Q_UNUSED(accessors); + return QV4::Encode::undefined(); +#endif +} + +ReturnedValue Runtime::method_accessQmlScopeObjectBoolProperty(const Value &context, + QQmlAccessors *accessors) +{ +#ifndef V4_BOOTSTRAP + const QmlContext &c = static_cast<const QmlContext &>(context); + bool rv = false; + accessors->read(c.d()->qml->scopeObject, &rv); + return QV4::Encode(rv); +#else + Q_UNUSED(context); + Q_UNUSED(accessors); + return QV4::Encode::undefined(); +#endif +} + +ReturnedValue Runtime::method_accessQmlScopeObjectQStringProperty(ExecutionEngine *engine, + const Value &context, + QQmlAccessors *accessors) +{ +#ifndef V4_BOOTSTRAP + const QmlContext &c = static_cast<const QmlContext &>(context); + QString rv; + accessors->read(c.d()->qml->scopeObject, &rv); + return QV4::Encode(engine->newString(rv)); +#else + Q_UNUSED(engine); + Q_UNUSED(context); + Q_UNUSED(accessors); + return QV4::Encode::undefined(); +#endif +} + #endif // V4_BOOTSTRAP } // namespace QV4 diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index ffae55995f..807fbe2f0e 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -140,349 +140,6 @@ inline double RuntimeHelpers::toNumber(const Value &value) { return value.toNumber(); } - -inline ReturnedValue Runtime::method_uPlus(const Value &value) -{ - TRACE1(value); - - if (value.isNumber()) - return value.asReturnedValue(); - if (value.integerCompatible()) - return Encode(value.int_32()); - - double n = value.toNumberImpl(); - return Encode(n); -} - -inline ReturnedValue Runtime::method_uMinus(const Value &value) -{ - TRACE1(value); - - // +0 != -0, so we need to convert to double when negating 0 - if (value.isInteger() && value.integerValue()) - return Encode(-value.integerValue()); - else { - double n = RuntimeHelpers::toNumber(value); - return Encode(-n); - } -} - -inline ReturnedValue Runtime::method_complement(const Value &value) -{ - TRACE1(value); - - int n = value.toInt32(); - return Encode((int)~n); -} - -inline ReturnedValue Runtime::method_uNot(const Value &value) -{ - TRACE1(value); - - bool b = value.toBoolean(); - return Encode(!b); -} - -// binary operators -inline ReturnedValue Runtime::method_bitOr(const Value &left, const Value &right) -{ - TRACE2(left, right); - - int lval = left.toInt32(); - int rval = right.toInt32(); - return Encode(lval | rval); -} - -inline ReturnedValue Runtime::method_bitXor(const Value &left, const Value &right) -{ - TRACE2(left, right); - - int lval = left.toInt32(); - int rval = right.toInt32(); - return Encode(lval ^ rval); -} - -inline ReturnedValue Runtime::method_bitAnd(const Value &left, const Value &right) -{ - TRACE2(left, right); - - int lval = left.toInt32(); - int rval = right.toInt32(); - return Encode(lval & rval); -} - -#ifndef V4_BOOTSTRAP -inline ReturnedValue Runtime::method_add(ExecutionEngine *engine, const Value &left, const Value &right) -{ - TRACE2(left, right); - - if (Q_LIKELY(left.isInteger() && right.isInteger())) - return add_int32(left.integerValue(), right.integerValue()); - if (left.isNumber() && right.isNumber()) - return Primitive::fromDouble(left.asDouble() + right.asDouble()).asReturnedValue(); - - return RuntimeHelpers::addHelper(engine, left, right); -} -#endif // V4_BOOTSTRAP - -inline ReturnedValue Runtime::method_sub(const Value &left, const Value &right) -{ - TRACE2(left, right); - - if (Q_LIKELY(left.isInteger() && right.isInteger())) - return sub_int32(left.integerValue(), right.integerValue()); - - double lval = left.isNumber() ? left.asDouble() : left.toNumberImpl(); - double rval = right.isNumber() ? right.asDouble() : right.toNumberImpl(); - - return Primitive::fromDouble(lval - rval).asReturnedValue(); -} - -inline ReturnedValue Runtime::method_mul(const Value &left, const Value &right) -{ - TRACE2(left, right); - - if (Q_LIKELY(left.isInteger() && right.isInteger())) - return mul_int32(left.integerValue(), right.integerValue()); - - double lval = left.isNumber() ? left.asDouble() : left.toNumberImpl(); - double rval = right.isNumber() ? right.asDouble() : right.toNumberImpl(); - - return Primitive::fromDouble(lval * rval).asReturnedValue(); -} - -inline ReturnedValue Runtime::method_div(const Value &left, const Value &right) -{ - TRACE2(left, right); - - if (Value::integerCompatible(left, right)) { - int lval = left.integerValue(); - int rval = right.integerValue(); - if (rval != 0 && (lval % rval == 0)) - return Encode(int(lval / rval)); - else - return Encode(double(lval) / rval); - } - - double lval = left.toNumber(); - double rval = right.toNumber(); - return Primitive::fromDouble(lval / rval).asReturnedValue(); -} - -inline ReturnedValue Runtime::method_mod(const Value &left, const Value &right) -{ - TRACE2(left, right); - - if (Value::integerCompatible(left, right) && right.integerValue() != 0) { - int intRes = left.integerValue() % right.integerValue(); - if (intRes != 0 || left.integerValue() >= 0) - return Encode(intRes); - } - - double lval = RuntimeHelpers::toNumber(left); - double rval = RuntimeHelpers::toNumber(right); - return Primitive::fromDouble(std::fmod(lval, rval)).asReturnedValue(); -} - -inline ReturnedValue Runtime::method_shl(const Value &left, const Value &right) -{ - TRACE2(left, right); - - int lval = left.toInt32(); - int rval = right.toInt32() & 0x1f; - return Encode((int)(lval << rval)); -} - -inline ReturnedValue Runtime::method_shr(const Value &left, const Value &right) -{ - TRACE2(left, right); - - int lval = left.toInt32(); - unsigned rval = right.toUInt32() & 0x1f; - return Encode((int)(lval >> rval)); -} - -inline ReturnedValue Runtime::method_ushr(const Value &left, const Value &right) -{ - TRACE2(left, right); - - unsigned lval = left.toUInt32(); - unsigned rval = right.toUInt32() & 0x1f; - uint res = lval >> rval; - - return Encode(res); -} - -inline ReturnedValue Runtime::method_greaterThan(const Value &left, const Value &right) -{ - TRACE2(left, right); - - bool r = method_compareGreaterThan(left, right); - return Encode(r); -} - -inline ReturnedValue Runtime::method_lessThan(const Value &left, const Value &right) -{ - TRACE2(left, right); - - bool r = method_compareLessThan(left, right); - return Encode(r); -} - -inline ReturnedValue Runtime::method_greaterEqual(const Value &left, const Value &right) -{ - TRACE2(left, right); - - bool r = method_compareGreaterEqual(left, right); - return Encode(r); -} - -inline ReturnedValue Runtime::method_lessEqual(const Value &left, const Value &right) -{ - TRACE2(left, right); - - bool r = method_compareLessEqual(left, right); - return Encode(r); -} - -inline Bool Runtime::method_compareEqual(const Value &left, const Value &right) -{ - TRACE2(left, right); - - if (left.rawValue() == right.rawValue()) - // NaN != NaN - return !left.isNaN(); - - if (left.type() == right.type()) { - if (!left.isManaged()) - return false; - if (left.isString() == right.isString()) - return left.cast<Managed>()->isEqualTo(right.cast<Managed>()); - } - - return RuntimeHelpers::equalHelper(left, right); -} - -inline ReturnedValue Runtime::method_equal(const Value &left, const Value &right) -{ - TRACE2(left, right); - - bool r = method_compareEqual(left, right); - return Encode(r); -} - -inline ReturnedValue Runtime::method_notEqual(const Value &left, const Value &right) -{ - TRACE2(left, right); - - bool r = !method_compareEqual(left, right); - return Encode(r); -} - -inline ReturnedValue Runtime::method_strictEqual(const Value &left, const Value &right) -{ - TRACE2(left, right); - - bool r = RuntimeHelpers::strictEqual(left, right); - return Encode(r); -} - -inline ReturnedValue Runtime::method_strictNotEqual(const Value &left, const Value &right) -{ - TRACE2(left, right); - - bool r = ! RuntimeHelpers::strictEqual(left, right); - return Encode(r); -} - -inline Bool Runtime::method_compareNotEqual(const Value &left, const Value &right) -{ - TRACE2(left, right); - - return !Runtime::method_compareEqual(left, right); -} - -inline Bool Runtime::method_compareStrictEqual(const Value &left, const Value &right) -{ - TRACE2(left, right); - - return RuntimeHelpers::strictEqual(left, right); -} - -inline Bool Runtime::method_compareStrictNotEqual(const Value &left, const Value &right) -{ - TRACE2(left, right); - - return ! RuntimeHelpers::strictEqual(left, right); -} - -inline Bool Runtime::method_toBoolean(const Value &value) -{ - return value.toBoolean(); -} - -inline ReturnedValue Runtime::method_accessQmlScopeObjectQRealProperty(const Value &context, - QQmlAccessors *accessors) -{ -#ifndef V4_BOOTSTRAP - const QmlContext &c = static_cast<const QmlContext &>(context); - qreal rv = 0; - accessors->read(c.d()->qml->scopeObject, &rv); - return QV4::Encode(rv); -#else - Q_UNUSED(context); - Q_UNUSED(accessors); - return QV4::Encode::undefined(); -#endif -} - -inline ReturnedValue Runtime::method_accessQmlScopeObjectIntProperty(const Value &context, - QQmlAccessors *accessors) -{ -#ifndef V4_BOOTSTRAP - const QmlContext &c = static_cast<const QmlContext &>(context); - int rv = 0; - accessors->read(c.d()->qml->scopeObject, &rv); - return QV4::Encode(rv); -#else - Q_UNUSED(context); - Q_UNUSED(accessors); - return QV4::Encode::undefined(); -#endif -} - -inline ReturnedValue Runtime::method_accessQmlScopeObjectBoolProperty(const Value &context, - QQmlAccessors *accessors) -{ -#ifndef V4_BOOTSTRAP - const QmlContext &c = static_cast<const QmlContext &>(context); - bool rv = false; - accessors->read(c.d()->qml->scopeObject, &rv); - return QV4::Encode(rv); -#else - Q_UNUSED(context); - Q_UNUSED(accessors); - return QV4::Encode::undefined(); -#endif -} - -inline ReturnedValue Runtime::method_accessQmlScopeObjectQStringProperty(ExecutionEngine *engine, - const Value &context, - QQmlAccessors *accessors) -{ -#ifndef V4_BOOTSTRAP - const QmlContext &c = static_cast<const QmlContext &>(context); - QString rv; - accessors->read(c.d()->qml->scopeObject, &rv); - return QV4::Encode(engine->newString(rv)); -#else - Q_UNUSED(engine); - Q_UNUSED(context); - Q_UNUSED(accessors); - return QV4::Encode::undefined(); -#endif -} - } // namespace QV4 QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index b97310c5b9..fa2409a85c 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -75,6 +75,9 @@ static void generateWarning(QV4::ExecutionEngine *v4, const QString& description // F(elementType, elementTypeName, sequenceType, defaultValue) #define FOREACH_QML_SEQUENCE_TYPE(F) \ + F(int, IntVector, QVector<int>, 0) \ + F(qreal, RealVector, QVector<qreal>, 0.0) \ + F(bool, BoolVector, QVector<bool>, false) \ F(int, Int, QList<int>, 0) \ F(qreal, Real, QList<qreal>, 0.0) \ F(bool, Bool, QList<bool>, false) \ @@ -578,6 +581,15 @@ Heap::QQmlSequence<Container>::QQmlSequence(QObject *object, int propertyIndex) namespace QV4 { +typedef QQmlSequence<QVector<int> > QQmlIntVectorList; +template<> +DEFINE_OBJECT_VTABLE(QQmlIntVectorList); +typedef QQmlSequence<QVector<qreal> > QQmlRealVectorList; +template<> +DEFINE_OBJECT_VTABLE(QQmlRealVectorList); +typedef QQmlSequence<QVector<bool> > QQmlBoolVectorList; +template<> +DEFINE_OBJECT_VTABLE(QQmlBoolVectorList); typedef QQmlSequence<QStringList> QQmlQStringList; template<> DEFINE_OBJECT_VTABLE(QQmlQStringList); diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp index abef885249..7c965ce441 100644 --- a/src/qml/jsruntime/qv4string.cpp +++ b/src/qml/jsruntime/qv4string.cpp @@ -46,12 +46,19 @@ #include "qv4stringobject_p.h" #endif #include <QtCore/QHash> +#include <QtCore/private/qnumeric_p.h> using namespace QV4; -static uint toArrayIndex(const QChar *ch, const QChar *end) +static inline uint toUInt(const QChar *ch) { return ch->unicode(); } +#ifndef V4_BOOTSTRAP +static inline uint toUInt(const char *ch) { return *ch; } +#endif + +template <typename T> +static inline uint toArrayIndex(const T *ch, const T *end) { - uint i = ch->unicode() - '0'; + uint i = toUInt(ch) - '0'; if (i > 9) return UINT_MAX; ++ch; @@ -60,14 +67,11 @@ static uint toArrayIndex(const QChar *ch, const QChar *end) return UINT_MAX; while (ch < end) { - uint x = ch->unicode() - '0'; + uint x = toUInt(ch) - '0'; if (x > 9) return UINT_MAX; - uint n = i*10 + x; - if (n < i) - // overflow + if (mul_overflow(i, uint(10), &i) || add_overflow(i, x, &i)) return UINT_MAX; - i = n; ++ch; } return i; @@ -75,30 +79,26 @@ static uint toArrayIndex(const QChar *ch, const QChar *end) #ifndef V4_BOOTSTRAP -static uint toArrayIndex(const char *ch, const char *end) +template <typename T> +static inline uint calculateHashValue(const T *ch, const T* end, uint *subtype) { - uint i = *ch - '0'; - if (i > 9) - return UINT_MAX; - ++ch; - // reject "01", "001", ... - if (i == 0 && ch != end) - return UINT_MAX; + // array indices get their number as hash value + uint h = ::toArrayIndex(ch, end); + if (h != UINT_MAX) { + if (subtype) + *subtype = Heap::String::StringType_ArrayIndex; + return h; + } while (ch < end) { - uint x = *ch - '0'; - if (x > 9) - return UINT_MAX; - uint n = i*10 + x; - if (n < i) - // overflow - return UINT_MAX; - i = n; + h = 31 * h + toUInt(ch); ++ch; } - return i; -} + if (subtype) + *subtype = Heap::String::StringType_Regular; + return h; +} DEFINE_MANAGED_VTABLE(String); @@ -198,31 +198,6 @@ void Heap::String::simplifyString() const mm->growUnmanagedHeapSizeUsage(size_t(text->size) * sizeof(QChar)); } -void Heap::String::createHashValue() const -{ - if (largestSubLength) - simplifyString(); - Q_ASSERT(!largestSubLength); - const QChar *ch = reinterpret_cast<const QChar *>(text->data()); - const QChar *end = ch + text->size; - - // array indices get their number as hash value - stringHash = ::toArrayIndex(ch, end); - if (stringHash != UINT_MAX) { - subtype = Heap::String::StringType_ArrayIndex; - return; - } - - uint h = 0xffffffff; - while (ch < end) { - h = 31 * h + ch->unicode(); - ++ch; - } - - stringHash = h; - subtype = Heap::String::StringType_Regular; -} - void Heap::String::append(const String *data, QChar *ch) { std::vector<const String *> worklist; @@ -243,45 +218,26 @@ void Heap::String::append(const String *data, QChar *ch) } } +void Heap::String::createHashValue() const +{ + if (largestSubLength) + simplifyString(); + Q_ASSERT(!largestSubLength); + const QChar *ch = reinterpret_cast<const QChar *>(text->data()); + const QChar *end = ch + text->size; + stringHash = calculateHashValue(ch, end, &subtype); +} - - -uint String::createHashValue(const QChar *ch, int length) +uint String::createHashValue(const QChar *ch, int length, uint *subtype) { const QChar *end = ch + length; - - // array indices get their number as hash value - uint stringHash = ::toArrayIndex(ch, end); - if (stringHash != UINT_MAX) - return stringHash; - - uint h = 0xffffffff; - while (ch < end) { - h = 31 * h + ch->unicode(); - ++ch; - } - - return h; + return calculateHashValue(ch, end, subtype); } -uint String::createHashValue(const char *ch, int length) +uint String::createHashValue(const char *ch, int length, uint *subtype) { const char *end = ch + length; - - // array indices get their number as hash value - uint stringHash = ::toArrayIndex(ch, end); - if (stringHash != UINT_MAX) - return stringHash; - - uint h = 0xffffffff; - while (ch < end) { - if ((uchar)(*ch) >= 0x80) - return UINT_MAX; - h = 31 * h + *ch; - ++ch; - } - - return h; + return calculateHashValue(ch, end, subtype); } uint String::getLength(const Managed *m) diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index 3196f49896..60e2655536 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -183,8 +183,8 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed { void makeIdentifierImpl(ExecutionEngine *e) const; - static uint createHashValue(const QChar *ch, int length); - static uint createHashValue(const char *ch, int length); + static uint createHashValue(const QChar *ch, int length, uint *subtype); + static uint createHashValue(const char *ch, int length, uint *subtype); bool startsWithUpper() const { const String::Data *l = d(); diff --git a/src/qml/parser/qqmljsparser_p.h b/src/qml/parser/qqmljsparser_p.h index 02dbe7d323..00ffb6aca3 100644 --- a/src/qml/parser/qqmljsparser_p.h +++ b/src/qml/parser/qqmljsparser_p.h @@ -174,7 +174,7 @@ public: inline DiagnosticMessage diagnosticMessage() const { - foreach (const DiagnosticMessage &d, diagnostic_messages) { + for (const DiagnosticMessage &d : diagnostic_messages) { if (d.kind != DiagnosticMessage::Warning) return d; } diff --git a/src/qml/qml/ftw/qhashedstring.cpp b/src/qml/qml/ftw/qhashedstring.cpp index 37c1003748..5c5d2a31ac 100644 --- a/src/qml/qml/ftw/qhashedstring.cpp +++ b/src/qml/qml/ftw/qhashedstring.cpp @@ -41,12 +41,12 @@ inline quint32 stringHash(const QChar* data, int length) { - return QV4::String::createHashValue(data, length); + return QV4::String::createHashValue(data, length, Q_NULLPTR); } inline quint32 stringHash(const char *data, int length) { - return QV4::String::createHashValue(data, length); + return QV4::String::createHashValue(data, length, Q_NULLPTR); } void QHashedString::computeHash() const diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index e8ddfecbe3..1249e1b6c8 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -168,7 +168,7 @@ void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags) return; } - QQmlBindingProfiler prof(ep->profiler, f); + QQmlBindingProfiler prof(ep->profiler, this, f); setUpdatingFlag(true); QQmlJavaScriptExpression::DeleteWatcher watcher(this); diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index 9879763c72..b03edc9020 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -56,7 +56,6 @@ #include <private/qv4value_p.h> -#include <QtCore/qstringbuilder.h> #include <QtCore/qdebug.h> @@ -81,9 +80,7 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, // Add some leading whitespace to account for the binding's column offset. // It's 2 off because a, we start counting at 1 and b, the '(' below is not counted. function.fill(QChar(QChar::Space), qMax(column, (quint16)2) - 2); - function += QStringLiteral("(function "); - function += handlerName; - function += QLatin1Char('('); + function += QStringLiteral("(function ") + handlerName + QLatin1Char('('); if (parameterString.isEmpty()) { QString error; @@ -99,10 +96,7 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, } else function += parameterString; - function += QStringLiteral(") { "); - function += expression; - function += QStringLiteral(" })"); - + function += QStringLiteral(") { ") + expression + QStringLiteral(" })"); m_function.set(v4, evalFunction(context(), scopeObject(), function, fileName, line)); if (m_function.isNullOrUndefined()) diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h index 1c43a85de3..cbe70a7077 100644 --- a/src/qml/qml/qqmlcompiler_p.h +++ b/src/qml/qml/qqmlcompiler_p.h @@ -89,8 +89,6 @@ public: QQmlEngine *engine; - QString fileName() const { return compilationUnit->fileName(); } - QUrl url() const { return compilationUnit->url(); } QQmlTypeNameCache *importCache; int metaTypeId; diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 61a4b701c0..6aa3710731 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -570,7 +570,7 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, QQmlCompiledData *cc, int start d->cc = cc; cc->addref(); d->start = start; - d->url = cc->url(); + d->url = cc->compilationUnit->url(); d->progress = 1.0; } diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 440840d3c9..18bee387dd 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -293,7 +293,7 @@ inline void QQmlEnginePrivate::dereferenceScarceResources() // if the refcount is zero, then evaluation of the "top level" // expression must have completed. We can safely release the // scarce resources. - if (scarceResourcesRefCount == 0) { + if (Q_LIKELY(scarceResourcesRefCount == 0)) { QV4::ExecutionEngine *engine = QV8Engine::getV4(v8engine()); if (Q_UNLIKELY(!engine->scarceResources.isEmpty())) { cleanupScarceResources(); diff --git a/src/qml/qml/qqmlerror.cpp b/src/qml/qml/qqmlerror.cpp index 47c85c907c..74ceeabeb4 100644 --- a/src/qml/qml/qqmlerror.cpp +++ b/src/qml/qml/qqmlerror.cpp @@ -43,6 +43,7 @@ #include <QtCore/qdebug.h> #include <QtCore/qfile.h> #include <QtCore/qstringlist.h> +#include <QtCore/qvector.h> #include <private/qv4errorobject_p.h> @@ -288,11 +289,11 @@ QDebug operator<<(QDebug debug, const QQmlError &error) stream.setCodec("UTF-8"); #endif const QString code = stream.readAll(); - const QStringList lines = code.split(QLatin1Char('\n')); + const auto lines = code.splitRef(QLatin1Char('\n')); if (lines.count() >= error.line()) { - const QString &line = lines.at(error.line() - 1); - debug << "\n " << qPrintable(line); + const QStringRef &line = lines.at(error.line() - 1); + debug << "\n " << line.toLocal8Bit().constData(); if(error.column() > 0) { int column = qMax(0, error.column() - 1); diff --git a/src/qml/qml/qqmlextensioninterface.h b/src/qml/qml/qqmlextensioninterface.h index 73e41a3b80..ef56d5e312 100644 --- a/src/qml/qml/qqmlextensioninterface.h +++ b/src/qml/qml/qqmlextensioninterface.h @@ -66,7 +66,7 @@ public: Q_DECLARE_INTERFACE(QQmlTypesExtensionInterface, "org.qt-project.Qt.QQmlTypesExtensionInterface/1.0") -#define QQmlExtensionInterface_iid "org.qt-project.Qt.QQmlExtensionInterface" +#define QQmlExtensionInterface_iid "org.qt-project.Qt.QQmlExtensionInterface/1.0" Q_DECLARE_INTERFACE(QQmlExtensionInterface, QQmlExtensionInterface_iid) diff --git a/src/qml/qml/qqmlfile.cpp b/src/qml/qml/qqmlfile.cpp index 7a441dd9ff..4769402855 100644 --- a/src/qml/qml/qqmlfile.cpp +++ b/src/qml/qml/qqmlfile.cpp @@ -605,7 +605,7 @@ QString QQmlFile::urlToLocalFileOrQrc(const QString& url) { if (url.startsWith(QLatin1String("qrc:"), Qt::CaseInsensitive)) { if (url.length() > 4) - return QLatin1Char(':') + url.mid(4); + return QLatin1Char(':') + url.midRef(4); return QString(); } diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index d6c81bcc49..01f1042de4 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -85,12 +85,11 @@ QString resolveLocalUrl(const QString &url, const QString &relative) } else if (relative.at(0) == Slash || !url.contains(Slash)) { return relative; } else { - QString base(url.left(url.lastIndexOf(Slash) + 1)); - + const QStringRef baseRef = url.leftRef(url.lastIndexOf(Slash) + 1); if (relative == QLatin1String(".")) - return base; + return baseRef.toString(); - base.append(relative); + QString base = baseRef + relative; // Remove any relative directory elements in the path int length = base.length(); @@ -192,7 +191,7 @@ void qmlClearEnginePlugins() { StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes(); QMutexLocker lock(&plugins->mutex); - foreach (RegisteredPlugin plugin, plugins->values()) { + for (auto &plugin : qAsConst(*plugins)) { QPluginLoader* loader = plugin.loader; if (loader && !loader->unload()) qWarning("Unloading %s failed: %s", qPrintable(plugin.uri), qPrintable(loader->errorString())); @@ -303,7 +302,7 @@ public: int vmaj, int vmin, QV4::CompiledData::Import::ImportType type, QList<QQmlError> *errors, bool lowPrecedence = false); #ifndef QT_NO_LIBRARY - bool populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri, + bool populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri, const QStringList &versionUris, const QString &qmldirPath, QList<QQmlError> *errors); #endif }; @@ -483,20 +482,58 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const return scripts; } +static QString joinStringRefs(const QVector<QStringRef> &refs, const QChar &sep) +{ + QString str; + for (auto it = refs.cbegin(); it != refs.cend(); ++it) { + if (it != refs.cbegin()) + str += sep; + str += *it; + } + return str; +} + /*! - Form a complete path to a qmldir file, from a base URL, a module URI and version specification. + Forms complete paths to a qmldir file, from a base URL, a module URI and version specification. + + For example, QtQml.Models 2.0: + - base/QtQml/Models.2.0/qmldir + - base/QtQml.2.0/Models/qmldir + - base/QtQml/Models.2/qmldir + - base/QtQml.2/Models/qmldir + - base/QtQml/Models/qmldir */ -QString QQmlImports::completeQmldirPath(const QString &uri, const QString &base, int vmaj, int vmin, - ImportVersion version) +QStringList QQmlImports::completeQmldirPaths(const QString &uri, const QStringList &basePaths, int vmaj, int vmin) { - QString url = uri; - url.replace(Dot, Slash); + const QVector<QStringRef> parts = uri.splitRef(Dot, QString::SkipEmptyParts); + + QStringList qmlDirPathsPaths; + // fully & partially versioned parts + 1 unversioned for each base path + qmlDirPathsPaths.reserve(basePaths.count() * (2 * parts.count() + 1)); + + for (int version = FullyVersioned; version <= Unversioned; ++version) { + const QString ver = versionString(vmaj, vmin, static_cast<QQmlImports::ImportVersion>(version)); + + for (const QString &path : basePaths) { + QString dir = path; + if (!dir.endsWith(Slash) && !dir.endsWith(Backslash)) + dir += Slash; - QString dir = base; - if (!dir.endsWith(Slash) && !dir.endsWith(Backslash)) - dir += Slash; + // append to the end + qmlDirPathsPaths += dir + joinStringRefs(parts, Slash) + ver + Slash_qmldir; - return dir + url + versionString(vmaj, vmin, version) + Slash_qmldir; + if (version != Unversioned) { + // insert in the middle + for (int index = parts.count() - 2; index >= 0; --index) { + qmlDirPathsPaths += dir + joinStringRefs(parts.mid(0, index + 1), Slash) + + ver + Slash + + joinStringRefs(parts.mid(index + 1), Slash) + Slash_qmldir; + } + } + } + } + + return qmlDirPathsPaths; } QString QQmlImports::versionString(int vmaj, int vmin, ImportVersion version) @@ -777,11 +814,11 @@ bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedS QString u1 = import->url; QString u2 = import2->url; if (base) { - QString b = *base; + QStringRef b(base); int dot = b.lastIndexOf(Dot); if (dot >= 0) { b = b.left(dot+1); - QString l = b.left(dot); + QStringRef l = b.left(dot); if (u1.startsWith(b)) u1 = u1.mid(b.count()); else if (u1 == l) @@ -841,14 +878,34 @@ QQmlImportNamespace *QQmlImportsPrivate::findQualifiedNamespace(const QHashedStr return 0; } +/*! + Returns the list of possible versioned URI combinations. For example, if \a uri is + QtQml.Models, \a vmaj is 2, and \a vmin is 0, this method returns the following: + [QtQml.Models.2.0, QtQml.2.0.Models, QtQml.Models.2, QtQml.2.Models, QtQml.Models] + */ +static QStringList versionUriList(const QString &uri, int vmaj, int vmin) +{ + QStringList result; + for (int version = QQmlImports::FullyVersioned; version <= QQmlImports::Unversioned; ++version) { + int index = uri.length(); + do { + QString versionUri = uri; + versionUri.insert(index, QQmlImports::versionString(vmaj, vmin, static_cast<QQmlImports::ImportVersion>(version))); + result += versionUri; + + index = uri.lastIndexOf(Dot, index - 1); + } while (index > 0 && version != QQmlImports::Unversioned); + } + return result; +} #ifndef QT_NO_LIBRARY /*! - Get all static plugins that are QML plugins and has a meta data URI that begins with \a uri. - Note that if e.g uri == "a", and different plugins have meta data "a", "a.2.1", "a.b.c", all - will be added to the result. So the result needs further version matching by the caller. + Get all static plugins that are QML plugins and has a meta data URI that matches with one of + \a versionUris, which is a list of all possible versioned URI combinations - see versionUriList() + above. */ -bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri, +bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri, const QStringList &versionUris, const QString &qmldirPath, QList<QQmlError> *errors) { static QVector<QStaticPlugin> plugins; @@ -856,8 +913,8 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res // To avoid traversing all static plugins for all imports, we cut down // the list the first time called to only contain QML plugins: foreach (const QStaticPlugin &plugin, QPluginLoader::staticPlugins()) { - if (qobject_cast<QQmlExtensionPlugin *>(plugin.instance())) - plugins.append(plugin); + if (plugin.metaData().value(QStringLiteral("IID")).toString() == QLatin1String(QQmlExtensionInterface_iid)) + plugins.append(plugin); } } @@ -877,7 +934,7 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res } // A plugin can be set up to handle multiple URIs, so go through the list: foreach (const QJsonValue &metaTagUri, metaTagsUriList) { - if (metaTagUri.toString().startsWith(uri)) { + if (versionUris.contains(metaTagUri.toString())) { result.append(qMakePair(plugin, metaTagsUriList)); break; } @@ -970,14 +1027,13 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, // versioned to unversioned, we need to compare with differnt version strings. If a module // has several plugins, they must all have the same version. Start by populating pluginPairs // with relevant plugins to cut the list short early on: + const QStringList versionUris = versionUriList(uri, vmaj, vmin); QVector<StaticPluginPair> pluginPairs; - if (!populatePluginPairVector(pluginPairs, uri, qmldirFilePath, errors)) + if (!populatePluginPairVector(pluginPairs, uri, versionUris, qmldirFilePath, errors)) return false; const QString basePath = QFileInfo(qmldirPath).absoluteFilePath(); - for (int version = QQmlImports::FullyVersioned; version <= QQmlImports::Unversioned && staticPluginsFound == 0; ++version) { - QString versionUri = uri + QQmlImports::versionString(vmaj, vmin, static_cast<QQmlImports::ImportVersion>(version)); - + for (const QString &versionUri : versionUris) { foreach (const StaticPluginPair &pair, pluginPairs) { foreach (const QJsonValue &metaTagUri, pair.second) { if (versionUri == metaTagUri.toString()) { @@ -998,6 +1054,8 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, } } } + if (staticPluginsFound > 0) + break; } } @@ -1130,32 +1188,29 @@ bool QQmlImportsPrivate::locateQmldir(const QString &uri, int vmaj, int vmin, QQ QStringList localImportPaths = database->importPathList(QQmlImportDatabase::Local); // Search local import paths for a matching version - for (int version = QQmlImports::FullyVersioned; version <= QQmlImports::Unversioned; ++version) { - foreach (const QString &path, localImportPaths) { - QString qmldirPath = QQmlImports::completeQmldirPath(uri, path, vmaj, vmin, static_cast<QQmlImports::ImportVersion>(version)); - - QString absoluteFilePath = typeLoader.absoluteFilePath(qmldirPath); - if (!absoluteFilePath.isEmpty()) { - QString url; - QString absolutePath = absoluteFilePath.left(absoluteFilePath.lastIndexOf(Slash)+1); - if (absolutePath.at(0) == Colon) - url = QLatin1String("qrc://") + absolutePath.mid(1); - else - url = QUrl::fromLocalFile(absolutePath).toString(); + const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(uri, localImportPaths, vmaj, vmin); + for (const QString &qmldirPath : qmlDirPaths) { + QString absoluteFilePath = typeLoader.absoluteFilePath(qmldirPath); + if (!absoluteFilePath.isEmpty()) { + QString url; + const QStringRef absolutePath = absoluteFilePath.leftRef(absoluteFilePath.lastIndexOf(Slash) + 1); + if (absolutePath.at(0) == Colon) + url = QLatin1String("qrc://") + absolutePath.mid(1); + else + url = QUrl::fromLocalFile(absolutePath.toString()).toString(); - QQmlImportDatabase::QmldirCache *cache = new QQmlImportDatabase::QmldirCache; - cache->versionMajor = vmaj; - cache->versionMinor = vmin; - cache->qmldirFilePath = absoluteFilePath; - cache->qmldirPathUrl = url; - cache->next = cacheHead; - database->qmldirCache.insert(uri, cache); + QQmlImportDatabase::QmldirCache *cache = new QQmlImportDatabase::QmldirCache; + cache->versionMajor = vmaj; + cache->versionMinor = vmin; + cache->qmldirFilePath = absoluteFilePath; + cache->qmldirPathUrl = url; + cache->next = cacheHead; + database->qmldirCache.insert(uri, cache); - *outQmldirFilePath = absoluteFilePath; - *outQmldirPathUrl = url; + *outQmldirFilePath = absoluteFilePath; + *outQmldirPathUrl = url; - return true; - } + return true; } } @@ -1647,10 +1702,7 @@ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader, resolvedPath += Slash; foreach (const QString &suffix, suffixes) { - QString pluginFileName = prefix; - - pluginFileName += baseName; - pluginFileName += suffix; + QString pluginFileName = prefix + baseName + suffix; QString absolutePath = typeLoader->absoluteFilePath(resolvedPath + pluginFileName); if (!absolutePath.isEmpty()) diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h index 628564ae34..0e7848730f 100644 --- a/src/qml/qml/qqmlimport_p.h +++ b/src/qml/qml/qqmlimport_p.h @@ -130,8 +130,7 @@ public: QList<CompositeSingletonReference> resolvedCompositeSingletons() const; - static QString completeQmldirPath(const QString &uri, const QString &base, int vmaj, int vmin, - QQmlImports::ImportVersion version); + static QStringList completeQmldirPaths(const QString &uri, const QStringList &basePaths, int vmaj, int vmin); static QString versionString(int vmaj, int vmin, ImportVersion version); static bool isLocal(const QString &url); diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp index 235aa1bf44..eba93bfb1a 100644 --- a/src/qml/qml/qqmlincubator.cpp +++ b/src/qml/qml/qqmlincubator.cpp @@ -281,7 +281,7 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i) if (!compiledData) return; - QML_MEMORY_SCOPE_URL(compiledData->url()); + QML_MEMORY_SCOPE_URL(compiledData->compilationUnit->url()); QExplicitlySharedDataPointer<QQmlIncubatorPrivate> protectThis(this); @@ -292,7 +292,7 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i) if (!vmeGuard.isOK()) { QQmlError error; - error.setUrl(compiledData->url()); + error.setUrl(compiledData->compilationUnit->url()); error.setDescription(QQmlComponent::tr("Object destroyed during incubation")); errors << error; progress = QQmlIncubatorPrivate::Completed; diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 576478b729..1c5a7ad8c1 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -1914,14 +1914,11 @@ QList<QQmlType*> QQmlMetaType::qmlSingletonTypes() QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - QList<QQmlType*> alltypes = data->nameToType.values(); QList<QQmlType*> retn; - foreach (QQmlType* t, alltypes) { - if (t->isSingleton()) { - retn.append(t); - } + for (const auto type : qAsConst(data->nameToType)) { + if (type->isSingleton()) + retn.append(type); } - return retn; } @@ -1929,9 +1926,9 @@ const QQmlPrivate::CachedQmlUnit *QQmlMetaType::findCachedCompilationUnit(const { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - for (QVector<QQmlPrivate::QmlUnitCacheLookupFunction>::ConstIterator it = data->lookupCachedQmlUnit.constBegin(), end = data->lookupCachedQmlUnit.constEnd(); - it != end; ++it) { - if (const QQmlPrivate::CachedQmlUnit *unit = (*it)(uri)) + + for (const auto lookup : qAsConst(data->lookupCachedQmlUnit)) { + if (const QQmlPrivate::CachedQmlUnit *unit = lookup(uri)) return unit; } return 0; @@ -1961,8 +1958,7 @@ QString QQmlMetaType::prettyTypeName(const QObject *object) marker = typeName.indexOf(QLatin1String("_QML_")); if (marker != -1) { - typeName = typeName.left(marker); - typeName += QLatin1Char('*'); + typeName = typeName.left(marker) + QLatin1Char('*'); type = QQmlMetaType::qmlType(QMetaType::type(typeName.toLatin1())); if (type) { typeName = type->qmlTypeName(); diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 29fff04325..8d3c5962bd 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -375,7 +375,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const QString string = binding->valueAsString(qmlUnit); // Encoded dir-separators defeat QUrl processing - decode them first string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive); - QUrl value = string.isEmpty() ? QUrl() : compiledData->url().resolved(QUrl(string)); + QUrl value = string.isEmpty() ? QUrl() : compiledData->compilationUnit->url().resolved(QUrl(string)); // Apply URL interceptor if (engine->urlInterceptor()) value = engine->urlInterceptor()->intercept(value, QQmlAbstractUrlInterceptor::UrlString); @@ -570,7 +570,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const } else if (property->propType == qMetaTypeId<QList<QUrl> >()) { Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String); QString urlString = binding->valueAsString(qmlUnit); - QUrl u = urlString.isEmpty() ? QUrl() : compiledData->url().resolved(QUrl(urlString)); + QUrl u = urlString.isEmpty() ? QUrl() : compiledData->compilationUnit->url().resolved(QUrl(urlString)); QList<QUrl> value; value.append(u); argv[0] = reinterpret_cast<void *>(&value); @@ -664,7 +664,7 @@ void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip) if (qmlTypeForObject(_bindingTarget)) { quint32 bindingSkipList = 0; - QQmlPropertyData *defaultProperty = _compiledObject->indexOfDefaultProperty != -1 ? _propertyCache->parent()->defaultProperty() : _propertyCache->defaultProperty(); + QQmlPropertyData *defaultProperty = _compiledObject->indexOfDefaultPropertyOrAlias != -1 ? _propertyCache->parent()->defaultProperty() : _propertyCache->defaultProperty(); const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable(); for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) { @@ -999,7 +999,7 @@ void QQmlObjectCreator::setupFunctions() void QQmlObjectCreator::recordError(const QV4::CompiledData::Location &location, const QString &description) { QQmlError error; - error.setUrl(compiledData->url()); + error.setUrl(compiledData->compilationUnit->url()); error.setLine(location.line); error.setColumn(location.column); error.setDescription(description); @@ -1037,8 +1037,8 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo if (compiledData->isComponent(index)) { isComponent = true; QQmlComponent *component = new QQmlComponent(engine, compiledData, index, parent); - Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(QStringLiteral("<component>"), - context->url(), obj->location.line, obj->location.column)); + Q_QML_OC_PROFILE(sharedState->profiler, profiler.update( + compiledData, obj, QStringLiteral("<component>"), context->url())); QQmlComponentPrivate::get(component)->creationContext = context; instance = component; ddata = QQmlData::get(instance, /*create*/true); @@ -1048,8 +1048,8 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo installPropertyCache = !typeRef->isFullyDynamicType; QQmlType *type = typeRef->type; if (type) { - Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(type->qmlTypeName(), - context->url(), obj->location.line, obj->location.column)); + Q_QML_OC_PROFILE(sharedState->profiler, profiler.update( + compiledData, obj, type->qmlTypeName(), context->url())); instance = type->create(); if (!instance) { recordError(obj->location, tr("Unable to create object of type %1").arg(stringAt(obj->inheritedTypeNameIndex))); @@ -1071,8 +1071,9 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo sharedState->allCreatedObjects.push(instance); } else { Q_ASSERT(typeRef->component); - Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(typeRef->component->fileName(), - context->url(), obj->location.line, obj->location.column)); + Q_QML_OC_PROFILE(sharedState->profiler, profiler.update( + compiledData, obj, typeRef->component->compilationUnit->fileName(), + context->url())); if (typeRef->component->compilationUnit->data->isSingleton()) { recordError(obj->location, tr("Composite Singleton Type %1 is not creatable").arg(stringAt(obj->inheritedTypeNameIndex))); @@ -1115,7 +1116,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo parserStatus->classBegin(); // push() the profiler state here, together with the parserStatus, as we'll pop() them // together, too. - Q_QML_OC_PROFILE(sharedState->profiler, sharedState->profiler.push(profiler)); + Q_QML_OC_PROFILE(sharedState->profiler, sharedState->profiler.push(obj)); sharedState->allParserStatusCallbacks.push(parserStatus); parserStatus->d = &sharedState->allParserStatusCallbacks.top(); } @@ -1288,7 +1289,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * if (!data.isEmpty()) { Q_ASSERT(!cache.isNull()); // install on _object - vmeMetaObject = new QQmlVMEMetaObject(_qobject, cache, reinterpret_cast<const QQmlVMEMetaData*>(data.constData())); + vmeMetaObject = new QQmlVMEMetaObject(_qobject, cache, reinterpret_cast<const QQmlVMEMetaData*>(data.constData()), compiledData->compilationUnit, _compiledObjectIndex); if (_ddata->propertyCache) _ddata->propertyCache->release(); _ddata->propertyCache = cache; diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 22de5e1ae9..df2ff05de1 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -58,6 +58,7 @@ #include <private/qv4functionobject_p.h> #include <QStringList> +#include <QVector> #include <private/qmetaobject_p.h> #include <private/qqmlvaluetypewrapper_p.h> #include <QtCore/qdebug.h> @@ -240,14 +241,14 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name) QQmlTypeNameCache *typeNameCache = context?context->imports:0; - QStringList path = name.split(QLatin1Char('.')); + const auto path = name.splitRef(QLatin1Char('.')); if (path.isEmpty()) return; QObject *currentObject = obj; // Everything up to the last property must be an "object type" property for (int ii = 0; ii < path.count() - 1; ++ii) { - const QString &pathName = path.at(ii); + const QStringRef &pathName = path.at(ii); if (typeNameCache) { QQmlTypeNameCache::Result r = typeNameCache->query(pathName); @@ -284,7 +285,7 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name) QQmlPropertyData local; QQmlPropertyData *property = - QQmlPropertyCache::property(engine, currentObject, pathName, context, local); + QQmlPropertyCache::property(engine, currentObject, pathName.toString(), context, local); if (!property) return; // Not a property if (property->isFunction()) @@ -324,14 +325,14 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name) } - const QString &terminal = path.last(); + const QStringRef &terminal = path.last(); if (terminal.count() >= 3 && terminal.at(0) == QLatin1Char('o') && terminal.at(1) == QLatin1Char('n') && terminal.at(2).isUpper()) { - QString signalName = terminal.mid(2); + QString signalName = terminal.mid(2).toString(); signalName[0] = signalName.at(0).toLower(); // XXX - this code treats methods as signals @@ -376,13 +377,14 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name) } // Property + const QString terminalString = terminal.toString(); QQmlPropertyData local; QQmlPropertyData *property = - QQmlPropertyCache::property(engine, currentObject, terminal, context, local); + QQmlPropertyCache::property(engine, currentObject, terminalString, context, local); if (property && !property->isFunction()) { object = currentObject; core = *property; - nameCache = terminal; + nameCache = terminalString; isNameCached = true; } } diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 15e8d62efc..c6299a1720 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -661,7 +661,7 @@ void QQmlDataBlob::notifyComplete(QQmlDataBlob *blob) Q_ASSERT(m_waitingFor.contains(blob)); Q_ASSERT(blob->status() == Error || blob->status() == Complete); QQmlCompilingProfiler prof(QQmlEnginePrivate::get(typeLoader()->engine())->profiler, - blob->url()); + blob); m_inCallback = true; @@ -1121,6 +1121,7 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob) } #define DATALOADER_MAXIMUM_REDIRECT_RECURSION 16 +#define TYPELOADER_MINIMUM_TRIM_THRESHOLD 64 #ifndef QT_NO_NETWORK void QQmlTypeLoader::networkReplyFinished(QNetworkReply *reply) @@ -1225,7 +1226,7 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, QQmlFile *file) void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::Data &d) { QML_MEMORY_SCOPE_URL(blob->url()); - QQmlCompilingProfiler prof(QQmlEnginePrivate::get(engine())->profiler, blob->url()); + QQmlCompilingProfiler prof(QQmlEnginePrivate::get(engine())->profiler, blob); blob->m_inCallback = true; @@ -1245,7 +1246,7 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::Data &d) void QQmlTypeLoader::setCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit) { QML_MEMORY_SCOPE_URL(blob->url()); - QQmlCompilingProfiler prof(QQmlEnginePrivate::get(engine())->profiler, blob->url()); + QQmlCompilingProfiler prof(QQmlEnginePrivate::get(engine())->profiler, blob); blob->m_inCallback = true; @@ -1398,13 +1399,10 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL // Probe for all possible locations int priority = 0; - for (int version = QQmlImports::FullyVersioned; version <= QQmlImports::Unversioned; ++version) { - foreach (const QString &path, remotePathList) { - QString qmldirUrl = QQmlImports::completeQmldirPath(importUri, path, import->majorVersion, import->minorVersion, - static_cast<QQmlImports::ImportVersion>(version)); - if (!fetchQmldir(QUrl(qmldirUrl), import, ++priority, errors)) - return false; - } + const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(importUri, remotePathList, import->majorVersion, import->minorVersion); + for (const QString &qmldirPath : qmlDirPaths) { + if (!fetchQmldir(QUrl(qmldirPath), import, ++priority, errors)) + return false; } } } @@ -1602,7 +1600,8 @@ bool QQmlTypeLoader::QmldirContent::designerSupported() const Constructs a new type loader that uses the given \a engine. */ QQmlTypeLoader::QQmlTypeLoader(QQmlEngine *engine) - : m_engine(engine), m_thread(new QQmlTypeLoaderThread(this)) + : m_engine(engine), m_thread(new QQmlTypeLoaderThread(this)), + m_typeCacheTrimThreshold(TYPELOADER_MINIMUM_TRIM_THRESHOLD) { } @@ -1639,6 +1638,10 @@ QQmlTypeData *QQmlTypeLoader::getType(const QUrl &url, Mode mode) QQmlTypeData *typeData = m_typeCache.value(url); if (!typeData) { + // Trim before adding the new type, so that we don't immediately trim it away + if (m_typeCache.size() >= m_typeCacheTrimThreshold) + trimCache(); + typeData = new QQmlTypeData(url, this); // TODO: if (compiledData == 0), is it safe to omit this insertion? m_typeCache.insert(url, typeData); @@ -1943,12 +1946,22 @@ void QQmlTypeLoader::clearCache() qDeleteAll(m_importQmlDirCache); m_typeCache.clear(); + m_typeCacheTrimThreshold = TYPELOADER_MINIMUM_TRIM_THRESHOLD; m_scriptCache.clear(); m_qmldirCache.clear(); m_importDirCache.clear(); m_importQmlDirCache.clear(); } +void QQmlTypeLoader::updateTypeCacheTrimThreshold() +{ + int size = m_typeCache.size(); + if (size > m_typeCacheTrimThreshold) + m_typeCacheTrimThreshold = size * 2; + if (size < m_typeCacheTrimThreshold / 2) + m_typeCacheTrimThreshold = qMax(size * 2, TYPELOADER_MINIMUM_TRIM_THRESHOLD); +} + void QQmlTypeLoader::trimCache() { while (true) { @@ -1973,6 +1986,8 @@ void QQmlTypeLoader::trimCache() } } + updateTypeCacheTrimThreshold(); + // TODO: release any scripts which are no longer referenced by any types } diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 49a4ac716a..12ab98e425 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -374,6 +374,7 @@ private: NetworkReplies m_networkReplies; #endif TypeCache m_typeCache; + int m_typeCacheTrimThreshold; ScriptCache m_scriptCache; QmldirCache m_qmldirCache; ImportDirCache m_importDirCache; @@ -381,6 +382,7 @@ private: template<typename Loader> void doLoad(const Loader &loader, QQmlDataBlob *blob, Mode mode); + void updateTypeCacheTrimThreshold(); friend struct PlainLoader; friend struct CachedLoader; diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp index d313557e98..fdac41a420 100644 --- a/src/qml/qml/qqmlvaluetypewrapper.cpp +++ b/src/qml/qml/qqmlvaluetypewrapper.cpp @@ -50,6 +50,7 @@ #include <private/qv4functionobject_p.h> #include <private/qv4variantobject_p.h> #include <private/qv4alloca_p.h> +#include <private/qv4objectiterator_p.h> QT_BEGIN_NAMESPACE @@ -244,6 +245,34 @@ PropertyAttributes QQmlValueTypeWrapper::query(const Managed *m, String *name) return result ? Attr_Data : Attr_Invalid; } +void QQmlValueTypeWrapper::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes) +{ + name->setM(0); + *index = UINT_MAX; + + QQmlValueTypeWrapper *that = static_cast<QQmlValueTypeWrapper*>(m); + + if (QQmlValueTypeReference *ref = that->as<QQmlValueTypeReference>()) { + if (!ref->readReferenceValue()) + return; + } + + if (that->d()->propertyCache) { + const QMetaObject *mo = that->d()->propertyCache->createMetaObject(); + const int propertyCount = mo->propertyCount(); + if (it->arrayIndex < static_cast<uint>(propertyCount)) { + Scope scope(that->engine()); + ScopedString propName(scope, that->engine()->newString(QString::fromUtf8(mo->property(it->arrayIndex).name()))); + name->setM(propName->d()); + ++it->arrayIndex; + *attributes = QV4::Attr_Data; + p->value = that->QV4::Object::get(propName); + return; + } + } + QV4::Object::advanceIterator(m, it, name, index, p, attributes); +} + bool QQmlValueTypeWrapper::isEqual(const QVariant& value) { if (QQmlValueTypeReference *ref = as<QQmlValueTypeReference>()) @@ -302,8 +331,7 @@ ReturnedValue QQmlValueTypeWrapper::method_toString(CallContext *ctx) if (QMetaType::convert(w->d()->gadgetPtr, w->d()->valueType->typeId, &convertResult, QMetaType::QString)) { result = convertResult; } else { - result = QString::fromUtf8(QMetaType::typeName(w->d()->valueType->typeId)); - result += QLatin1Char('('); + result = QString::fromUtf8(QMetaType::typeName(w->d()->valueType->typeId)) + QLatin1Char('('); const QMetaObject *mo = w->d()->propertyCache->metaObject(); const int propCount = mo->propertyCount(); for (int i = 0; i < propCount; ++i) { diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h index c2861f5bfa..94eeba366a 100644 --- a/src/qml/qml/qqmlvaluetypewrapper_p.h +++ b/src/qml/qml/qqmlvaluetypewrapper_p.h @@ -99,6 +99,7 @@ public: static void put(Managed *m, String *name, const Value &value); static bool isEqualTo(Managed *m, Managed *other); static PropertyAttributes query(const Managed *, String *name); + static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); static QV4::ReturnedValue method_toString(CallContext *ctx); diff --git a/src/qml/qml/qqmlvme_p.h b/src/qml/qml/qqmlvme_p.h index a59d8e2aec..ac9db5c046 100644 --- a/src/qml/qml/qqmlvme_p.h +++ b/src/qml/qml/qqmlvme_p.h @@ -64,8 +64,6 @@ #include <private/qqmlengine_p.h> #include <private/qfinitestack_p.h> -#include <private/qqmlprofiler_p.h> - QT_BEGIN_NAMESPACE class QObject; diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index ef00a582ef..b0b7995ae2 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -99,10 +99,10 @@ void QQmlVMEVariantQObjectPtr::objectDestroyed(QObject *) return; if (m_index >= 0) { - QV4::ExecutionEngine *v4 = m_target->properties.engine(); + QV4::ExecutionEngine *v4 = m_target->propertyAndMethodStorage.engine(); if (v4) { QV4::Scope scope(v4); - QV4::Scoped<QV4::MemberData> sp(scope, m_target->properties.value()); + QV4::Scoped<QV4::MemberData> sp(scope, m_target->propertyAndMethodStorage.value()); if (sp) *(sp->data() + m_index) = QV4::Primitive::nullValue(); } @@ -140,17 +140,19 @@ void QQmlVMEMetaObjectEndpoint_callback(QQmlNotifierEndpoint *e, void **) void QQmlVMEMetaObjectEndpoint::tryConnect() { + Q_ASSERT(metaObject->compiledObject); int aliasId = this - metaObject->aliasEndpoints; if (metaObject.flag()) { // This is actually notify - int sigIdx = metaObject->methodOffset() + aliasId + metaObject->metaData->propertyCount; + int sigIdx = metaObject->methodOffset() + aliasId + metaObject->compiledObject->nProperties; metaObject->activate(metaObject->object, sigIdx, 0); } else { + const QV4::CompiledData::Alias *aliasData = &metaObject->compiledObject->aliasTable()[aliasId]; QQmlVMEMetaData::AliasData *d = metaObject->metaData->aliasData() + aliasId; - if (!d->isObjectAlias()) { + if (!aliasData->isObjectAlias()) { QQmlContextData *ctxt = metaObject->ctxt; - QObject *target = ctxt->idValues[d->contextIdx].data(); + QObject *target = ctxt->idValues[aliasData->targetObjectId].data(); if (!target) return; @@ -304,135 +306,128 @@ QAbstractDynamicMetaObject *QQmlInterceptorMetaObject::toDynamicMetaObject(QObje QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj, QQmlPropertyCache *cache, - const QQmlVMEMetaData *meta) + const QQmlVMEMetaData *meta, QV4::CompiledData::CompilationUnit *qmlCompilationUnit, int qmlObjectId) : QQmlInterceptorMetaObject(obj, cache), ctxt(QQmlData::get(obj, true)->outerContext), metaData(meta), - aliasEndpoints(0), - methods(0) + aliasEndpoints(0), compilationUnit(qmlCompilationUnit), compiledObject(0) { cache->addref(); QQmlData::get(obj)->hasVMEMetaObject = true; - int qobject_type = qMetaTypeId<QObject*>(); - int variant_type = qMetaTypeId<QVariant>(); - // Need JS wrapper to ensure properties are marked. - // ### FIXME: I hope that this can be removed once we have the proper scope chain - // set up and the JS wrappers always exist. - bool needsJSWrapper = (metaData->propertyCount > 0); - - // ### Optimize - for (int ii = 0; ii < metaData->propertyCount; ++ii) { - int t = (metaData->propertyData() + ii)->propertyType; - if (t == qobject_type || t == variant_type) { - needsJSWrapper = true; - break; + if (compilationUnit && qmlObjectId >= 0) { + compiledObject = compilationUnit->data->objectAt(qmlObjectId); + + if (compiledObject->nProperties || compiledObject->nFunctions) { + Q_ASSERT(cache && cache->engine); + QV4::ExecutionEngine *v4 = cache->engine; + QV4::Heap::MemberData *data = QV4::MemberData::allocate(v4, compiledObject->nProperties + compiledObject->nFunctions); + propertyAndMethodStorage.set(v4, data); + std::fill(data->data, data->data + data->size, QV4::Encode::undefined()); + + // Need JS wrapper to ensure properties/methods are marked. + ensureQObjectWrapper(); } } - - if (needsJSWrapper) - ensureQObjectWrapper(); } QQmlVMEMetaObject::~QQmlVMEMetaObject() { if (parent.isT1()) parent.asT1()->objectDestroyed(object); delete [] aliasEndpoints; - delete [] methods; qDeleteAll(varObjectGuards); cache->release(); } -QV4::MemberData *QQmlVMEMetaObject::propertiesAsMemberData() +QV4::MemberData *QQmlVMEMetaObject::propertyAndMethodStorageAsMemberData() { - if (properties.isUndefined()) { - if (properties.valueRef()) + if (propertyAndMethodStorage.isUndefined()) { + if (propertyAndMethodStorage.valueRef()) // in some situations, the QObject wrapper (and associated data, // such as the varProperties array) will have been cleaned up, but the // QObject ptr will not yet have been deleted (eg, waiting on deleteLater). // In this situation, return 0. return 0; - allocateProperties(); } - return static_cast<QV4::MemberData*>(properties.asManaged()); + return static_cast<QV4::MemberData*>(propertyAndMethodStorage.asManaged()); } void QQmlVMEMetaObject::writeProperty(int id, int v) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) *(md->data() + id) = QV4::Primitive::fromInt32(v); } void QQmlVMEMetaObject::writeProperty(int id, bool v) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) *(md->data() + id) = QV4::Primitive::fromBoolean(v); } void QQmlVMEMetaObject::writeProperty(int id, double v) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) *(md->data() + id) = QV4::Primitive::fromDouble(v); } void QQmlVMEMetaObject::writeProperty(int id, const QString& v) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) *(md->data() + id) = cache->engine->newString(v); } void QQmlVMEMetaObject::writeProperty(int id, const QUrl& v) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); } void QQmlVMEMetaObject::writeProperty(int id, const QDate& v) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); } void QQmlVMEMetaObject::writeProperty(int id, const QDateTime& v) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); } void QQmlVMEMetaObject::writeProperty(int id, const QPointF& v) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); } void QQmlVMEMetaObject::writeProperty(int id, const QSizeF& v) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); } void QQmlVMEMetaObject::writeProperty(int id, const QRectF& v) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); } void QQmlVMEMetaObject::writeProperty(int id, QObject* v) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) *(md->data() + id) = QV4::QObjectWrapper::wrap(cache->engine, v); @@ -447,7 +442,7 @@ void QQmlVMEMetaObject::writeProperty(int id, QObject* v) int QQmlVMEMetaObject::readPropertyAsInt(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return 0; @@ -460,7 +455,7 @@ int QQmlVMEMetaObject::readPropertyAsInt(int id) bool QQmlVMEMetaObject::readPropertyAsBool(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return false; @@ -473,7 +468,7 @@ bool QQmlVMEMetaObject::readPropertyAsBool(int id) double QQmlVMEMetaObject::readPropertyAsDouble(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return 0.0; @@ -486,7 +481,7 @@ double QQmlVMEMetaObject::readPropertyAsDouble(int id) QString QQmlVMEMetaObject::readPropertyAsString(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return QString(); @@ -499,7 +494,7 @@ QString QQmlVMEMetaObject::readPropertyAsString(int id) QUrl QQmlVMEMetaObject::readPropertyAsUrl(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return QUrl(); @@ -513,7 +508,7 @@ QUrl QQmlVMEMetaObject::readPropertyAsUrl(int id) QDate QQmlVMEMetaObject::readPropertyAsDate(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return QDate(); @@ -527,7 +522,7 @@ QDate QQmlVMEMetaObject::readPropertyAsDate(int id) QDateTime QQmlVMEMetaObject::readPropertyAsDateTime(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return QDateTime(); @@ -541,7 +536,7 @@ QDateTime QQmlVMEMetaObject::readPropertyAsDateTime(int id) QSizeF QQmlVMEMetaObject::readPropertyAsSizeF(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return QSizeF(); @@ -555,7 +550,7 @@ QSizeF QQmlVMEMetaObject::readPropertyAsSizeF(int id) QPointF QQmlVMEMetaObject::readPropertyAsPointF(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return QPointF(); @@ -569,7 +564,7 @@ QPointF QQmlVMEMetaObject::readPropertyAsPointF(int id) QObject* QQmlVMEMetaObject::readPropertyAsQObject(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return 0; @@ -583,7 +578,7 @@ QObject* QQmlVMEMetaObject::readPropertyAsQObject(int id) QList<QObject *> *QQmlVMEMetaObject::readPropertyAsList(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return 0; @@ -599,7 +594,7 @@ QList<QObject *> *QQmlVMEMetaObject::readPropertyAsList(int id) QRectF QQmlVMEMetaObject::readPropertyAsRectF(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return QRectF(); @@ -621,15 +616,20 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * if (intercept(c, _id, a)) return -1; + const int propertyCount = compiledObject ? int(compiledObject->nProperties) : 0; + const int aliasCount = compiledObject ? int(compiledObject->nAliases) : 0; + const int signalCount = compiledObject ? int(compiledObject->nSignals) : 0; + const int methodCount = compiledObject ? int(compiledObject->nFunctions) : 0; + if (c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty || c == QMetaObject::ResetProperty) { if (id >= propOffset()) { id -= propOffset(); - if (id < metaData->propertyCount) { - int t = (metaData->propertyData() + id)->propertyType; + if (id < propertyCount) { + const QV4::CompiledData::Property::Type t = static_cast<QV4::CompiledData::Property::Type>(compiledObject->propertyTable()[id].type); bool needActivate = false; - if (t == QQmlVMEMetaData::VarPropertyType) { + if (t == QV4::CompiledData::Property::Var) { // the context can be null if accessing var properties from cpp after re-parenting an item. QQmlEnginePrivate *ep = (ctxt == 0 || ctxt->engine == 0) ? 0 : QQmlEnginePrivate::get(ctxt->engine); QV8Engine *v8e = (ep == 0) ? 0 : ep->v8engine(); @@ -645,131 +645,179 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * } } else { + int fallbackMetaType = QMetaType::UnknownType; + switch (t) { + case QV4::CompiledData::Property::Font: + fallbackMetaType = QMetaType::QFont; + break; + case QV4::CompiledData::Property::Time: + fallbackMetaType = QMetaType::QTime; + break; + case QV4::CompiledData::Property::Color: + fallbackMetaType = QMetaType::QColor; + break; + case QV4::CompiledData::Property::Vector2D: + fallbackMetaType = QMetaType::QVector2D; + break; + case QV4::CompiledData::Property::Vector3D: + fallbackMetaType = QMetaType::QVector3D; + break; + case QV4::CompiledData::Property::Vector4D: + fallbackMetaType = QMetaType::QVector4D; + break; + case QV4::CompiledData::Property::Matrix4x4: + fallbackMetaType = QMetaType::QMatrix4x4; + break; + case QV4::CompiledData::Property::Quaternion: + fallbackMetaType = QMetaType::QQuaternion; + break; + default: break; + } + if (c == QMetaObject::ReadProperty) { - switch(t) { - case QVariant::Int: + switch (t) { + case QV4::CompiledData::Property::Int: *reinterpret_cast<int *>(a[0]) = readPropertyAsInt(id); break; - case QVariant::Bool: + case QV4::CompiledData::Property::Bool: *reinterpret_cast<bool *>(a[0]) = readPropertyAsBool(id); break; - case QVariant::Double: + case QV4::CompiledData::Property::Real: *reinterpret_cast<double *>(a[0]) = readPropertyAsDouble(id); break; - case QVariant::String: + case QV4::CompiledData::Property::String: *reinterpret_cast<QString *>(a[0]) = readPropertyAsString(id); break; - case QVariant::Url: + case QV4::CompiledData::Property::Url: *reinterpret_cast<QUrl *>(a[0]) = readPropertyAsUrl(id); break; - case QVariant::Date: + case QV4::CompiledData::Property::Date: *reinterpret_cast<QDate *>(a[0]) = readPropertyAsDate(id); break; - case QVariant::DateTime: + case QV4::CompiledData::Property::DateTime: *reinterpret_cast<QDateTime *>(a[0]) = readPropertyAsDateTime(id); break; - case QVariant::RectF: + case QV4::CompiledData::Property::Rect: *reinterpret_cast<QRectF *>(a[0]) = readPropertyAsRectF(id); break; - case QVariant::SizeF: + case QV4::CompiledData::Property::Size: *reinterpret_cast<QSizeF *>(a[0]) = readPropertyAsSizeF(id); break; - case QVariant::PointF: + case QV4::CompiledData::Property::Point: *reinterpret_cast<QPointF *>(a[0]) = readPropertyAsPointF(id); break; - case QMetaType::QObjectStar: + case QV4::CompiledData::Property::Custom: *reinterpret_cast<QObject **>(a[0]) = readPropertyAsQObject(id); break; - case QMetaType::QVariant: + case QV4::CompiledData::Property::Variant: *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id); break; - default: - { - if (t == qMetaTypeId<QQmlListProperty<QObject> >()) { - QList<QObject *> *list = readPropertyAsList(id); - QQmlListProperty<QObject> *p = static_cast<QQmlListProperty<QObject> *>(a[0]); - *p = QQmlListProperty<QObject>(object, list, - list_append, list_count, list_at, - list_clear); - p->dummy1 = this; - p->dummy2 = reinterpret_cast<void *>(quintptr(methodOffset() + id)); - } else { - QV4::MemberData *md = propertiesAsMemberData(); - if (md) { - QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); - if (v) - QQml_valueTypeProvider()->readValueType(v->d()->data, a[0], t); - } - } + case QV4::CompiledData::Property::CustomList: { + QList<QObject *> *list = readPropertyAsList(id); + QQmlListProperty<QObject> *p = static_cast<QQmlListProperty<QObject> *>(a[0]); + *p = QQmlListProperty<QObject>(object, list, + list_append, list_count, list_at, + list_clear); + p->dummy1 = this; + p->dummy2 = reinterpret_cast<void *>(quintptr(methodOffset() + id)); break; } + case QV4::CompiledData::Property::Font: + case QV4::CompiledData::Property::Time: + case QV4::CompiledData::Property::Color: + case QV4::CompiledData::Property::Vector2D: + case QV4::CompiledData::Property::Vector3D: + case QV4::CompiledData::Property::Vector4D: + case QV4::CompiledData::Property::Matrix4x4: + case QV4::CompiledData::Property::Quaternion: + Q_ASSERT(fallbackMetaType != QMetaType::UnknownType); + if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) { + QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); + if (v) + QQml_valueTypeProvider()->readValueType(v->d()->data, a[0], fallbackMetaType); + } + break; + case QV4::CompiledData::Property::Var: + Q_UNREACHABLE(); } } else if (c == QMetaObject::WriteProperty) { switch(t) { - case QVariant::Int: + case QV4::CompiledData::Property::Int: needActivate = *reinterpret_cast<int *>(a[0]) != readPropertyAsInt(id); writeProperty(id, *reinterpret_cast<int *>(a[0])); break; - case QVariant::Bool: + case QV4::CompiledData::Property::Bool: needActivate = *reinterpret_cast<bool *>(a[0]) != readPropertyAsBool(id); writeProperty(id, *reinterpret_cast<bool *>(a[0])); break; - case QVariant::Double: + case QV4::CompiledData::Property::Real: needActivate = *reinterpret_cast<double *>(a[0]) != readPropertyAsDouble(id); writeProperty(id, *reinterpret_cast<double *>(a[0])); break; - case QVariant::String: + case QV4::CompiledData::Property::String: needActivate = *reinterpret_cast<QString *>(a[0]) != readPropertyAsString(id); writeProperty(id, *reinterpret_cast<QString *>(a[0])); break; - case QVariant::Url: + case QV4::CompiledData::Property::Url: needActivate = *reinterpret_cast<QUrl *>(a[0]) != readPropertyAsUrl(id); writeProperty(id, *reinterpret_cast<QUrl *>(a[0])); break; - case QVariant::Date: + case QV4::CompiledData::Property::Date: needActivate = *reinterpret_cast<QDate *>(a[0]) != readPropertyAsDate(id); writeProperty(id, *reinterpret_cast<QDate *>(a[0])); break; - case QVariant::DateTime: + case QV4::CompiledData::Property::DateTime: needActivate = *reinterpret_cast<QDateTime *>(a[0]) != readPropertyAsDateTime(id); writeProperty(id, *reinterpret_cast<QDateTime *>(a[0])); break; - case QVariant::RectF: + case QV4::CompiledData::Property::Rect: needActivate = *reinterpret_cast<QRectF *>(a[0]) != readPropertyAsRectF(id); writeProperty(id, *reinterpret_cast<QRectF *>(a[0])); break; - case QVariant::SizeF: + case QV4::CompiledData::Property::Size: needActivate = *reinterpret_cast<QSizeF *>(a[0]) != readPropertyAsSizeF(id); writeProperty(id, *reinterpret_cast<QSizeF *>(a[0])); break; - case QVariant::PointF: + case QV4::CompiledData::Property::Point: needActivate = *reinterpret_cast<QPointF *>(a[0]) != readPropertyAsPointF(id); writeProperty(id, *reinterpret_cast<QPointF *>(a[0])); break; - case QMetaType::QObjectStar: + case QV4::CompiledData::Property::Custom: needActivate = *reinterpret_cast<QObject **>(a[0]) != readPropertyAsQObject(id); writeProperty(id, *reinterpret_cast<QObject **>(a[0])); break; - case QMetaType::QVariant: + case QV4::CompiledData::Property::Variant: writeProperty(id, *reinterpret_cast<QVariant *>(a[0])); break; - default: { - QV4::MemberData *md = propertiesAsMemberData(); - if (md) { + case QV4::CompiledData::Property::CustomList: + // Writing such a property is not supported. Content is added through the list property + // methods. + break; + case QV4::CompiledData::Property::Font: + case QV4::CompiledData::Property::Time: + case QV4::CompiledData::Property::Color: + case QV4::CompiledData::Property::Vector2D: + case QV4::CompiledData::Property::Vector3D: + case QV4::CompiledData::Property::Vector4D: + case QV4::CompiledData::Property::Matrix4x4: + case QV4::CompiledData::Property::Quaternion: + Q_ASSERT(fallbackMetaType != QMetaType::UnknownType); + if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) { QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); if (!v) { *(md->data() + id) = cache->engine->newVariantObject(QVariant()); v = (md->data() + id)->as<QV4::VariantObject>(); - QQml_valueTypeProvider()->initValueType(t, v->d()->data); + QQml_valueTypeProvider()->initValueType(fallbackMetaType, v->d()->data); } - needActivate = !QQml_valueTypeProvider()->equalValueType(t, a[0], v->d()->data); - QQml_valueTypeProvider()->writeValueType(t, a[0], v->d()->data); + needActivate = !QQml_valueTypeProvider()->equalValueType(fallbackMetaType, a[0], v->d()->data); + QQml_valueTypeProvider()->writeValueType(fallbackMetaType, a[0], v->d()->data); } break; - } + case QV4::CompiledData::Property::Var: + Q_UNREACHABLE(); } } @@ -782,13 +830,12 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * return -1; } - id -= metaData->propertyCount; + id -= propertyCount; - if (id < metaData->aliasCount) { + if (id < aliasCount) { + const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[id]; - QQmlVMEMetaData::AliasData *d = metaData->aliasData() + id; - - if (d->flags & QML_ALIAS_FLAG_PTR && c == QMetaObject::ReadProperty) + if ((aliasData->flags & QV4::CompiledData::Alias::AliasPointsToPointerObject) && c == QMetaObject::ReadProperty) *reinterpret_cast<void **>(a[0]) = 0; if (!ctxt) return -1; @@ -796,42 +843,52 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * QQmlContext *context = ctxt->asQQmlContext(); QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(context); - QObject *target = ctxtPriv->data->idValues[d->contextIdx].data(); + QObject *target = ctxtPriv->data->idValues[aliasData->targetObjectId].data(); if (!target) return -1; connectAlias(id); - if (d->isObjectAlias()) { + if (aliasData->isObjectAlias()) { *reinterpret_cast<QObject **>(a[0]) = target; return -1; } + QQmlData *targetDData = QQmlData::get(target, /*create*/false); + if (!targetDData) + return -1; + + int coreIndex; + const int valueTypePropertyIndex = QQmlPropertyData::decodeValueTypePropertyIndex(aliasData->encodedMetaPropertyIndex, &coreIndex); + // Remove binding (if any) on write if(c == QMetaObject::WriteProperty) { int flags = *reinterpret_cast<int*>(a[3]); if (flags & QQmlPropertyPrivate::RemoveBindingOnAliasWrite) { QQmlData *targetData = QQmlData::get(target); - if (targetData && targetData->hasBindingBit(d->propertyIndex())) - QQmlPropertyPrivate::removeBinding(target, d->propertyIdx); + if (targetData && targetData->hasBindingBit(coreIndex)) + QQmlPropertyPrivate::removeBinding(target, aliasData->encodedMetaPropertyIndex); } } - if (d->isValueTypeAlias()) { + if (valueTypePropertyIndex != -1) { + if (!targetDData->propertyCache) + return -1; + const QQmlPropertyData *pd = targetDData->propertyCache->property(coreIndex); // Value type property - QQmlValueType *valueType = QQmlValueTypeFactory::valueType(d->valueType()); + QQmlValueType *valueType = QQmlValueTypeFactory::valueType(pd->propType); Q_ASSERT(valueType); - valueType->read(target, d->propertyIndex()); - int rv = QMetaObject::metacall(valueType, c, d->valueTypeIndex(), a); + valueType->read(target, coreIndex); + int rv = QMetaObject::metacall(valueType, c, valueTypePropertyIndex, a); if (c == QMetaObject::WriteProperty) - valueType->write(target, d->propertyIndex(), 0x00); + valueType->write(target, coreIndex, 0x00); return rv; } else { - return QMetaObject::metacall(target, c, d->propertyIndex(), a); + return QMetaObject::metacall(target, c, coreIndex, a); } } @@ -844,8 +901,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * if (id >= methodOffset()) { id -= methodOffset(); - int plainSignals = metaData->signalCount + metaData->propertyCount + - metaData->aliasCount; + int plainSignals = signalCount + propertyCount + aliasCount; if (id < plainSignals) { activate(object, _id, a); return -1; @@ -853,7 +909,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * id -= plainSignals; - if (id < metaData->methodCount) { + if (id < methodCount) { if (!ctxt->engine) return -1; // We can't run the method @@ -877,12 +933,11 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * return -1; // The dynamic method with that id is not available. } - QQmlVMEMetaData::MethodData *data = metaData->methodData() + id; - - QV4::ScopedCallData callData(scope, data->parameterCount); + const unsigned int parameterCount = function->formalParameterCount(); + QV4::ScopedCallData callData(scope, parameterCount); callData->thisObject = ep->v8engine()->global(); - for (int ii = 0; ii < data->parameterCount; ++ii) + for (uint ii = 0; ii < parameterCount; ++ii) callData->args[ii] = scope.engine->fromVariant(*(QVariant *)a[ii + 1]); QV4::ScopedValue result(scope); @@ -911,22 +966,23 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * QV4::ReturnedValue QQmlVMEMetaObject::method(int index) { - if (!ctxt || !ctxt->isValid()) { + if (!ctxt || !ctxt->isValid() || !compiledObject) { qWarning("QQmlVMEMetaObject: Internal error - attempted to evaluate a function in an invalid context"); return QV4::Encode::undefined(); } - if (!methods) + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); + if (!md) return QV4::Encode::undefined(); - return methods[index].value(); + return (md->data() + index + compiledObject->nProperties)->asReturnedValue(); } QV4::ReturnedValue QQmlVMEMetaObject::readVarProperty(int id) { - Q_ASSERT((metaData->propertyData() + id)->propertyType == QQmlVMEMetaData::VarPropertyType); + Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].type == QV4::CompiledData::Property::Var); - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) return (md->data() + id)->asReturnedValue(); return QV4::Primitive::undefinedValue().asReturnedValue(); @@ -934,7 +990,7 @@ QV4::ReturnedValue QQmlVMEMetaObject::readVarProperty(int id) QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) { const QV4::QObjectWrapper *wrapper = (md->data() + id)->as<QV4::QObjectWrapper>(); if (wrapper) @@ -949,9 +1005,9 @@ QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id) void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value) { - Q_ASSERT((metaData->propertyData() + id)->propertyType == QQmlVMEMetaData::VarPropertyType); + Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].type == QV4::CompiledData::Property::Var); - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return; @@ -989,8 +1045,8 @@ void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value) void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) { - if ((metaData->propertyData() + id)->propertyType == QQmlVMEMetaData::VarPropertyType) { - QV4::MemberData *md = propertiesAsMemberData(); + if (compiledObject && compiledObject->propertyTable()[id].type == QV4::CompiledData::Property::Var) { + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return; @@ -1020,7 +1076,7 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) needActivate = readPropertyAsQObject(id) != o; // TODO: still correct? writeProperty(id, o); } else { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) { QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); needActivate = (!v || @@ -1039,30 +1095,16 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) } } -quint16 QQmlVMEMetaObject::vmeMethodLineNumber(int index) -{ - if (index < methodOffset()) { - Q_ASSERT(parentVMEMetaObject()); - return parentVMEMetaObject()->vmeMethodLineNumber(index); - } - - int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount; - Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + metaData->methodCount)); - - int rawIndex = index - methodOffset() - plainSignals; - - QQmlVMEMetaData::MethodData *data = metaData->methodData() + rawIndex; - return data->lineNumber; -} - QV4::ReturnedValue QQmlVMEMetaObject::vmeMethod(int index) { if (index < methodOffset()) { Q_ASSERT(parentVMEMetaObject()); return parentVMEMetaObject()->vmeMethod(index); } - int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount; - Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + metaData->methodCount)); + if (!compiledObject) + return QV4::Primitive::undefinedValue().asReturnedValue(); + const int plainSignals = compiledObject->nSignals + compiledObject->nProperties + compiledObject->nAliases; + Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + int(compiledObject->nFunctions))); return method(index - methodOffset() - plainSignals); } @@ -1073,14 +1115,16 @@ void QQmlVMEMetaObject::setVmeMethod(int index, const QV4::Value &function) Q_ASSERT(parentVMEMetaObject()); return parentVMEMetaObject()->setVmeMethod(index, function); } - int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount; - Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + metaData->methodCount)); - - if (!methods) - methods = new QV4::PersistentValue[metaData->methodCount]; + if (!compiledObject) + return; + const int plainSignals = compiledObject->nSignals + compiledObject->nProperties + compiledObject->nAliases; + Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + int(compiledObject->nFunctions))); int methodIndex = index - methodOffset() - plainSignals; - methods[methodIndex].set(function.as<QV4::Object>()->engine(), function); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); + if (!md) + return; + *(md->data() + methodIndex + compiledObject->nProperties) = function; } QV4::ReturnedValue QQmlVMEMetaObject::vmeProperty(int index) @@ -1115,25 +1159,15 @@ void QQmlVMEMetaObject::mark(QV4::ExecutionEngine *e) if (v4 != e) return; - properties.markOnce(e); + propertyAndMethodStorage.markOnce(e); if (QQmlVMEMetaObject *parent = parentVMEMetaObject()) parent->mark(e); } -void QQmlVMEMetaObject::allocateProperties() -{ - Q_ASSERT(cache && cache->engine); - Q_ASSERT(!properties.valueRef()); - QV4::ExecutionEngine *v4 = cache->engine; - QV4::Heap::MemberData *data = QV4::MemberData::allocate(v4, metaData->propertyCount); - properties.set(v4, data); - std::fill(data->data, data->data + data->size, QV4::Encode::undefined()); -} - bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const { - Q_ASSERT(index >= propOffset() + metaData->propertyCount); + Q_ASSERT(compiledObject && (index >= propOffset() + int(compiledObject->nProperties))); *target = 0; *coreIndex = -1; @@ -1142,31 +1176,24 @@ bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, if (!ctxt) return false; - QQmlVMEMetaData::AliasData *d = metaData->aliasData() + (index - propOffset() - metaData->propertyCount); - QQmlContext *context = ctxt->asQQmlContext(); - QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(context); - - *target = ctxtPriv->data->idValues[d->contextIdx].data(); + const int aliasId = index - propOffset() - compiledObject->nProperties; + const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[aliasId]; + *target = ctxt->idValues[aliasData->targetObjectId].data(); if (!*target) return false; - if (d->isObjectAlias()) { - } else if (d->isValueTypeAlias()) { - *coreIndex = d->propertyIndex(); - *valueTypeIndex = d->valueTypeIndex(); - } else { - *coreIndex = d->propertyIndex(); - } - + if (!aliasData->isObjectAlias()) + *valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(aliasData->encodedMetaPropertyIndex, coreIndex); return true; } void QQmlVMEMetaObject::connectAlias(int aliasId) { + Q_ASSERT(compiledObject); if (!aliasEndpoints) - aliasEndpoints = new QQmlVMEMetaObjectEndpoint[metaData->aliasCount]; + aliasEndpoints = new QQmlVMEMetaObjectEndpoint[compiledObject->nAliases]; - QQmlVMEMetaData::AliasData *d = metaData->aliasData() + aliasId; + const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[aliasId]; QQmlVMEMetaObjectEndpoint *endpoint = aliasEndpoints + aliasId; if (endpoint->metaObject.data()) { @@ -1176,14 +1203,15 @@ void QQmlVMEMetaObject::connectAlias(int aliasId) } endpoint->metaObject = this; - endpoint->connect(&ctxt->idValues[d->contextIdx].bindings); + endpoint->connect(&ctxt->idValues[aliasData->targetObjectId].bindings); endpoint->tryConnect(); } void QQmlVMEMetaObject::connectAliasSignal(int index, bool indexInSignalRange) { - int aliasId = (index - (indexInSignalRange ? signalOffset() : methodOffset())) - metaData->propertyCount; - if (aliasId < 0 || aliasId >= metaData->aliasCount) + Q_ASSERT(compiledObject); + int aliasId = (index - (indexInSignalRange ? signalOffset() : methodOffset())) - compiledObject->nProperties; + if (aliasId < 0 || aliasId >= int(compiledObject->nAliases)) return; connectAlias(aliasId); diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h index fcdac3cc53..f9f9ec47af 100644 --- a/src/qml/qml/qqmlvmemetaobject_p.h +++ b/src/qml/qml/qqmlvmemetaobject_p.h @@ -74,69 +74,17 @@ QT_BEGIN_NAMESPACE -#define QML_ALIAS_FLAG_PTR 0x00000001 - struct QQmlVMEMetaData { - short propertyCount; - short aliasCount; - short signalCount; - short methodCount; // Make sure this structure is always aligned to int + int dummy; struct AliasData { - int contextIdx; - int propertyIdx; - int propType; - int flags; int notifySignal; - - bool isObjectAlias() const { - return propertyIdx == -1; - } - bool isPropertyAlias() const { - return !isObjectAlias() && valueTypeIndex() == -1; - } - bool isValueTypeAlias() const { - return !isObjectAlias() && valueTypeIndex() != -1; - } - int propertyIndex() const { - int index; - QQmlPropertyData::decodeValueTypePropertyIndex(propertyIdx, &index); - return index; - } - int valueTypeIndex() const { - return QQmlPropertyData::decodeValueTypePropertyIndex(propertyIdx); - } - int valueType() const { - return (valueTypeIndex() != -1) ? propType : 0; - } - }; - - enum { - VarPropertyType = -1 }; - struct PropertyData { - int propertyType; - }; - - struct MethodData { - int runtimeFunctionIndex; - int parameterCount; - quint16 lineNumber; - }; - - PropertyData *propertyData() const { - return (PropertyData *)(((char *)const_cast<QQmlVMEMetaData *>(this)) + sizeof(QQmlVMEMetaData)); - } - AliasData *aliasData() const { - return (AliasData *)(propertyData() + propertyCount); - } - - MethodData *methodData() const { - return (MethodData *)(aliasData() + aliasCount); + return (AliasData *)(((char *)const_cast<QQmlVMEMetaData *>(this)) + sizeof(QQmlVMEMetaData)); } }; @@ -199,12 +147,11 @@ class QQmlVMEMetaObjectEndpoint; class Q_QML_PRIVATE_EXPORT QQmlVMEMetaObject : public QQmlInterceptorMetaObject { public: - QQmlVMEMetaObject(QObject *obj, QQmlPropertyCache *cache, const QQmlVMEMetaData *data); + QQmlVMEMetaObject(QObject *obj, QQmlPropertyCache *cache, const QQmlVMEMetaData *data, QV4::CompiledData::CompilationUnit *qmlCompilationUnit, int qmlObjectId); ~QQmlVMEMetaObject(); bool aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const; QV4::ReturnedValue vmeMethod(int index); - quint16 vmeMethodLineNumber(int index); void setVmeMethod(int index, const QV4::Value &function); QV4::ReturnedValue vmeProperty(int index); void setVMEProperty(int index, const QV4::Value &v); @@ -230,9 +177,8 @@ public: QQmlVMEMetaObjectEndpoint *aliasEndpoints; - QV4::WeakValue properties; - inline void allocateProperties(); - QV4::MemberData *propertiesAsMemberData(); + QV4::WeakValue propertyAndMethodStorage; + QV4::MemberData *propertyAndMethodStorageAsMemberData(); int readPropertyAsInt(int id); bool readPropertyAsBool(int id); @@ -265,7 +211,6 @@ public: void connectAlias(int aliasId); - QV4::PersistentValue *methods; QV4::ReturnedValue method(int); QV4::ReturnedValue readVarProperty(int); @@ -280,6 +225,12 @@ public: QList<QQmlVMEVariantQObjectPtr *> varObjectGuards; QQmlVMEVariantQObjectPtr *getQObjectGuardForProperty(int) const; + + + // keep a reference to the compilation unit in order to still + // do property access when the context has been invalidated. + QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit; + const QV4::CompiledData::Object *compiledObject; }; QQmlVMEMetaObject *QQmlVMEMetaObject::get(QObject *obj) diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index ac40b627d9..1f42cbf983 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -88,22 +88,18 @@ struct StaticQtMetaObject : public QObject }; Heap::QtObject::QtObject(QQmlEngine *qmlEngine) + : enumeratorIterator(0) + , keyIterator(0) { Scope scope(internalClass->engine); ScopedObject o(scope, this); - // Set all the enums from the "Qt" namespace - const QMetaObject *qtMetaObject = StaticQtMetaObject::get(); - ScopedString str(scope); - ScopedValue v(scope); - for (int ii = 0; ii < qtMetaObject->enumeratorCount(); ++ii) { - QMetaEnum enumerator = qtMetaObject->enumerator(ii); - for (int jj = 0; jj < enumerator.keyCount(); ++jj) { - o->put((str = scope.engine->newString(QString::fromUtf8(enumerator.key(jj)))), (v = QV4::Primitive::fromInt32(enumerator.value(jj)))); - } + { + ScopedString str(scope); + ScopedValue v(scope); + o->put((str = scope.engine->newString(QStringLiteral("Asynchronous"))), (v = QV4::Primitive::fromInt32(0))); + o->put((str = scope.engine->newString(QStringLiteral("Synchronous"))), (v = QV4::Primitive::fromInt32(1))); } - o->put((str = scope.engine->newString(QStringLiteral("Asynchronous"))), (v = QV4::Primitive::fromInt32(0))); - o->put((str = scope.engine->newString(QStringLiteral("Synchronous"))), (v = QV4::Primitive::fromInt32(1))); o->defineDefaultProperty(QStringLiteral("include"), QV4Include::method_include); o->defineDefaultProperty(QStringLiteral("isQtObject"), QV4::QtObject::method_isQtObject); @@ -154,6 +150,70 @@ Heap::QtObject::QtObject(QQmlEngine *qmlEngine) o->defineDefaultProperty(QStringLiteral("callLater"), QV4::QtObject::method_callLater); } +void QtObject::addAll() +{ + bool dummy = false; + findAndAdd(nullptr, dummy); +} + +ReturnedValue QtObject::findAndAdd(const QString *name, bool &foundProperty) const +{ + Scope scope(engine()); + ScopedObject o(scope, this); + ScopedString key(scope); + ScopedValue value(scope); + + const QMetaObject *qtMetaObject = StaticQtMetaObject::get(); + for (int enumCount = qtMetaObject->enumeratorCount(); d()->enumeratorIterator < enumCount; + ++d()->enumeratorIterator) { + QMetaEnum enumerator = qtMetaObject->enumerator(d()->enumeratorIterator); + for (int keyCount = enumerator.keyCount(); d()->keyIterator < keyCount; ++d()->keyIterator) { + key = scope.engine->newString(QString::fromUtf8(enumerator.key(d()->keyIterator))); + value = QV4::Primitive::fromInt32(enumerator.value(d()->keyIterator)); + o->put(key, value); + if (name && key->toQString() == *name) { + ++d()->keyIterator; + foundProperty = true; + return value->asReturnedValue(); + } + } + d()->keyIterator = 0; + } + d()->enumeratorIterator = Heap::QtObject::Finished; + foundProperty = false; + return Encode::undefined(); +} + +ReturnedValue QtObject::get(const Managed *m, String *name, bool *hasProperty) +{ + bool hasProp = false; + if (hasProperty == nullptr) { + hasProperty = &hasProp; + } + + ReturnedValue ret = QV4::Object::get(m, name, hasProperty); + if (*hasProperty) { + return ret; + } + + auto that = static_cast<const QtObject*>(m); + if (!that->d()->isComplete()) { + const QString key = name->toQString(); + ret = that->findAndAdd(&key, *hasProperty); + } + + return ret; +} + +void QtObject::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes) +{ + auto that = static_cast<QtObject*>(m); + if (!that->d()->isComplete()) { + that->addAll(); + } + + QV4::Object::advanceIterator(m, it, name, index, p, attributes); +} /*! \qmlmethod bool Qt::isQtObject(object) diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h index 99c8b69724..5404ab3616 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h +++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h @@ -67,6 +67,13 @@ struct QtObject : Object { QtObject(QQmlEngine *qmlEngine); QObject *platform; QObject *application; + + enum { Finished = -1 }; + int enumeratorIterator; + int keyIterator; + + bool isComplete() const + { return enumeratorIterator == Finished; } }; struct ConsoleObject : Object { @@ -86,6 +93,9 @@ struct QtObject : Object { V4_OBJECT2(QtObject, Object) + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); + static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); + static ReturnedValue method_isQtObject(CallContext *ctx); static ReturnedValue method_rgba(CallContext *ctx); static ReturnedValue method_hsla(CallContext *ctx); @@ -126,6 +136,10 @@ struct QtObject : Object static ReturnedValue method_get_styleHints(CallContext *ctx); static ReturnedValue method_callLater(CallContext *ctx); + +private: + void addAll(); + ReturnedValue findAndAdd(const QString *name, bool &foundProperty) const; }; struct ConsoleObject : Object diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index 73128f6344..d8b0ef79f8 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -156,8 +156,7 @@ QV8Engine::QV8Engine(QJSEngine* qq) QV8Engine::~QV8Engine() { - for (int ii = 0; ii < m_extensionData.count(); ++ii) - delete m_extensionData[ii]; + qDeleteAll(m_extensionData); m_extensionData.clear(); #if !defined(QT_NO_XMLSTREAMREADER) && defined(QT_NO_NETWORK) diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index 6e5fa516db..aee9fcd0a2 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -1040,7 +1040,7 @@ QString QQmlDelegateModelPrivate::stringValue(Compositor::Group group, int index return QString(); int from = dot+1; dot = name.indexOf(QLatin1Char('.'), from); - value = obj->property(name.mid(from, dot-from).toUtf8()); + value = obj->property(name.midRef(from, dot - from).toUtf8()); } return value.toString(); } @@ -1557,29 +1557,6 @@ bool QQmlDelegateModel::isDescendantOf(const QPersistentModelIndex& desc, const return false; } -void QQmlDelegateModel::_q_layoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint) -{ - Q_D(QQmlDelegateModel); - if (!d->m_complete) - return; - - if (hint == QAbstractItemModel::VerticalSortHint) { - d->m_storedPersistentIndexes.clear(); - if (!parents.isEmpty() && d->m_adaptorModel.rootIndex.isValid() && !isDescendantOf(d->m_adaptorModel.rootIndex, parents)) { - return; - } - - for (int i = 0; i < d->m_count; ++i) { - const QModelIndex index = d->m_adaptorModel.aim()->index(i, 0, d->m_adaptorModel.rootIndex); - d->m_storedPersistentIndexes.append(index); - } - } else if (hint == QAbstractItemModel::HorizontalSortHint) { - // Ignored - } else { - // Triggers model reset, no preparations for that are needed - } -} - void QQmlDelegateModel::_q_layoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint) { Q_D(QQmlDelegateModel); @@ -1591,19 +1568,7 @@ void QQmlDelegateModel::_q_layoutChanged(const QList<QPersistentModelIndex> &par return; } - for (int i = 0, c = d->m_storedPersistentIndexes.count(); i < c; ++i) { - const QPersistentModelIndex &index = d->m_storedPersistentIndexes.at(i); - if (i == index.row()) - continue; - - _q_itemsMoved(i, index.row(), 1); - } - - d->m_storedPersistentIndexes.clear(); - - // layoutUpdate does not necessarily have any move changes, but it can - // also mean data changes. We can't detect what exactly has changed, so - // just emit it for all items + // mark all items as changed _q_itemsChanged(0, d->m_count, QVector<int>()); } else if (hint == QAbstractItemModel::HorizontalSortHint) { diff --git a/src/qml/types/qqmldelegatemodel_p.h b/src/qml/types/qqmldelegatemodel_p.h index aea474de67..2986ec7ce5 100644 --- a/src/qml/types/qqmldelegatemodel_p.h +++ b/src/qml/types/qqmldelegatemodel_p.h @@ -146,7 +146,6 @@ private Q_SLOTS: void _q_rowsRemoved(const QModelIndex &,int,int); void _q_rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int); void _q_dataChanged(const QModelIndex&,const QModelIndex&,const QVector<int> &); - void _q_layoutAboutToBeChanged(const QList<QPersistentModelIndex>&, QAbstractItemModel::LayoutChangeHint); void _q_layoutChanged(const QList<QPersistentModelIndex>&, QAbstractItemModel::LayoutChangeHint); private: diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h index 8e2d1c1cb3..76e55f718d 100644 --- a/src/qml/types/qqmldelegatemodel_p_p.h +++ b/src/qml/types/qqmldelegatemodel_p_p.h @@ -337,8 +337,6 @@ public: }; QQmlDelegateModelGroup *m_groups[Compositor::MaximumGroupCount]; }; - - QList<QPersistentModelIndex> m_storedPersistentIndexes; }; class QQmlPartsModel : public QQmlInstanceModel, public QQmlDelegateModelGroupEmitter diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp index 15c547b5df..5fc2444b7c 100644 --- a/src/qml/util/qqmladaptormodel.cpp +++ b/src/qml/util/qqmladaptormodel.cpp @@ -470,8 +470,6 @@ public: vdm, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int))); QObject::disconnect(aim, SIGNAL(modelReset()), vdm, SLOT(_q_modelReset())); - QObject::disconnect(aim, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)), - vdm, SLOT(_q_layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint))); QObject::disconnect(aim, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)), vdm, SLOT(_q_layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint))); } @@ -928,8 +926,6 @@ void QQmlAdaptorModel::setModel(const QVariant &variant, QQmlDelegateModel *vdm, vdm, QQmlDelegateModel, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int))); qmlobject_connect(model, QAbstractItemModel, SIGNAL(modelReset()), vdm, QQmlDelegateModel, SLOT(_q_modelReset())); - qmlobject_connect(model, QAbstractItemModel, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)), - vdm, QQmlDelegateModel, SLOT(_q_layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint))); qmlobject_connect(model, QAbstractItemModel, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)), vdm, QQmlDelegateModel, SLOT(_q_layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint))); } else { diff --git a/src/qmltest/quicktest.cpp b/src/qmltest/quicktest.cpp index 9ba93a1241..bc26a19033 100644 --- a/src/qmltest/quicktest.cpp +++ b/src/qmltest/quicktest.cpp @@ -352,7 +352,7 @@ int quick_test_main(int argc, char **argv, const char *name, const char *sourceD QTestRootObject::instance()->init(); QString path = fi.absoluteFilePath(); if (path.startsWith(QLatin1String(":/"))) - view->setSource(QUrl(QLatin1String("qrc:") + path.mid(2))); + view->setSource(QUrl(QLatin1String("qrc:") + path.midRef(2))); else view->setSource(QUrl::fromLocalFile(path)); diff --git a/src/quick/designer/qqmldesignermetaobject.cpp b/src/quick/designer/qqmldesignermetaobject.cpp index 46808f978b..63b4102b10 100644 --- a/src/quick/designer/qqmldesignermetaobject.cpp +++ b/src/quick/designer/qqmldesignermetaobject.cpp @@ -79,23 +79,9 @@ struct MetaPropertyData { QVector<QPair<QVariant, bool> > m_data; }; -static bool constructedMetaData(const QQmlVMEMetaData* data) -{ - return data->propertyCount == 0 - && data->aliasCount == 0 - && data->signalCount == 0 - && data->methodCount == 0; -} - static QQmlVMEMetaData* fakeMetaData() { - QQmlVMEMetaData* data = new QQmlVMEMetaData; - data->propertyCount = 0; - data->aliasCount = 0; - data->signalCount = 0; - data->methodCount = 0; - - return data; + return new QQmlVMEMetaData; } static const QQmlVMEMetaData* vMEMetaDataForObject(QObject *object) @@ -125,7 +111,15 @@ QQmlDesignerMetaObject* QQmlDesignerMetaObject::getNodeInstanceMetaObject(QObjec return static_cast<QQmlDesignerMetaObject *>(parent); // we just create one and the ownership goes automatically to the object in nodeinstance see init method - return new QQmlDesignerMetaObject(object, engine); + + QQmlData *ddata = QQmlData::get(object, false); + + const bool hadVMEMetaObject = ddata ? ddata->hasVMEMetaObject : false; + QQmlDesignerMetaObject *mo = new QQmlDesignerMetaObject(object, engine); + //If our parent is not a VMEMetaObject we just set the flag to false again + if (ddata) + ddata->hasVMEMetaObject = hadVMEMetaObject; + return mo; } void QQmlDesignerMetaObject::init(QObject *object, QQmlEngine *engine) @@ -140,20 +134,20 @@ void QQmlDesignerMetaObject::init(QObject *object, QQmlEngine *engine) QObjectPrivate *op = QObjectPrivate::get(object); op->metaObject = this; - //create cache - cache = m_cache = QQmlEnginePrivate::get(engine)->cache(this); - cache->addref(); + m_cache = QQmlEnginePrivate::get(engine)->cache(this); - //If our parent is not a VMEMetaObject we just se the flag to false again - if (constructedMetaData(metaData)) - QQmlData::get(object)->hasVMEMetaObject = false; + if (m_cache != cache) { + m_cache->addref(); + cache->release(); + cache = m_cache; + } nodeInstanceMetaObjectList.insert(this, true); hasAssignedMetaObjectData = true; } QQmlDesignerMetaObject::QQmlDesignerMetaObject(QObject *object, QQmlEngine *engine) - : QQmlVMEMetaObject(object, cacheForObject(object, engine), vMEMetaDataForObject(object)), + : QQmlVMEMetaObject(object, cacheForObject(object, engine), vMEMetaDataForObject(object), /*qml compilation unit*/nullptr, /*qmlObjectId*/-1), m_context(engine->contextForObject(object)), m_data(new MetaPropertyData), m_cache(0) @@ -161,22 +155,20 @@ QQmlDesignerMetaObject::QQmlDesignerMetaObject(QObject *object, QQmlEngine *engi init(object, engine); QQmlData *ddata = QQmlData::get(object, false); - //Assign cache to object if (ddata && ddata->propertyCache) { cache->setParent(ddata->propertyCache); cache->invalidate(engine, this); + ddata->propertyCache->release(); ddata->propertyCache = m_cache; + m_cache->addref(); } } QQmlDesignerMetaObject::~QQmlDesignerMetaObject() { - if (cache->count() > 1) // qml is crashing because the property cache is not removed from the engine - cache->release(); - else - m_type->release(); + m_type->release(); nodeInstanceMetaObjectList.remove(this); } diff --git a/src/quick/designer/qqmldesignermetaobject_p.h b/src/quick/designer/qqmldesignermetaobject_p.h index c45f83dc1e..a5402ccbc4 100644 --- a/src/quick/designer/qqmldesignermetaobject_p.h +++ b/src/quick/designer/qqmldesignermetaobject_p.h @@ -70,7 +70,6 @@ public: static void registerNotifyPropertyChangeCallBack(void (*callback)(QObject*, const QQuickDesignerSupport::PropertyName &propertyName)); protected: - QQmlDesignerMetaObject(QObject *object, QQmlEngine *engine); static QQmlDesignerMetaObject* getNodeInstanceMetaObject(QObject *object, QQmlEngine *engine); void createNewDynamicProperty(const QString &name); @@ -95,6 +94,7 @@ protected: void copyTypeMetaObject(); private: + QQmlDesignerMetaObject(QObject *object, QQmlEngine *engine); void init(QObject *, QQmlEngine *engine); QPointer<QQmlContext> m_context; diff --git a/src/quick/designer/qquickdesignersupport.cpp b/src/quick/designer/qquickdesignersupport.cpp index ec00eed18a..f063cd3a81 100644 --- a/src/quick/designer/qquickdesignersupport.cpp +++ b/src/quick/designer/qquickdesignersupport.cpp @@ -189,17 +189,17 @@ QTransform QQuickDesignerSupport::parentTransform(QQuickItem *referencedItem) return parentTransform; } -QString propertyNameForAnchorLine(const QQuickAnchorLine::AnchorLine &anchorLine) +QString propertyNameForAnchorLine(const QQuickAnchors::Anchor &anchorLine) { switch (anchorLine) { - case QQuickAnchorLine::Left: return QLatin1String("left"); - case QQuickAnchorLine::Right: return QLatin1String("right"); - case QQuickAnchorLine::Top: return QLatin1String("top"); - case QQuickAnchorLine::Bottom: return QLatin1String("bottom"); - case QQuickAnchorLine::HCenter: return QLatin1String("horizontalCenter"); - case QQuickAnchorLine::VCenter: return QLatin1String("verticalCenter"); - case QQuickAnchorLine::Baseline: return QLatin1String("baseline"); - case QQuickAnchorLine::Invalid: + case QQuickAnchors::LeftAnchor: return QLatin1String("left"); + case QQuickAnchors::RightAnchor: return QLatin1String("right"); + case QQuickAnchors::TopAnchor: return QLatin1String("top"); + case QQuickAnchors::BottomAnchor: return QLatin1String("bottom"); + case QQuickAnchors::HCenterAnchor: return QLatin1String("horizontalCenter"); + case QQuickAnchors::VCenterAnchor: return QLatin1String("verticalCenter"); + case QQuickAnchors::BaselineAnchor: return QLatin1String("baseline"); + case QQuickAnchors::InvalidAnchor: // fallthrough: default: return QString(); } } @@ -345,7 +345,7 @@ QPair<QString, QObject*> QQuickDesignerSupport::anchorLineTarget(QQuickItem *ite return QPair<QString, QObject*>(); QQuickAnchorLine anchorLine = metaProperty.read().value<QQuickAnchorLine>(); - if (anchorLine.anchorLine != QQuickAnchorLine::Invalid) { + if (anchorLine.anchorLine != QQuickAnchors::InvalidAnchor) { targetObject = anchorLine.item; targetName = propertyNameForAnchorLine(anchorLine.anchorLine); } diff --git a/src/quick/doc/snippets/qml/externaldrag.qml b/src/quick/doc/snippets/qml/externaldrag.qml new file mode 100644 index 0000000000..096a7702b4 --- /dev/null +++ b/src/quick/doc/snippets/qml/externaldrag.qml @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +//![0] +import QtQuick 2.8 + +Item { + width: 200; height: 200 + + Rectangle { + anchors.centerIn: parent + width: text.implicitWidth + 20; height: text.implicitHeight + 10 + color: "green" + radius: 5 + + Drag.active: dragArea.drag.active + Drag.dragType: Drag.Automatic + Drag.supportedActions: Qt.CopyAction + Drag.mimeData: { + "text/plain": "Copied text" + } + + Text { + id: text + anchors.centerIn: parent + text: "Drag me" + } + + MouseArea { + id: dragArea + anchors.fill: parent + + drag.target: parent + onPressed: parent.grabToImage(function(result) { + parent.Drag.imageSource = result.url + }) + } + } +} +//![0] diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp index b43adac0c5..7e7b1fa062 100644 --- a/src/quick/items/context2d/qquickcontext2d.cpp +++ b/src/quick/items/context2d/qquickcontext2d.cpp @@ -66,6 +66,7 @@ #include <private/qv4scopedvalue_p.h> #include <QtCore/qmath.h> +#include <QtCore/qvector.h> #include <QtCore/private/qnumeric_p.h> #include <QtCore/QRunnable> #include <QtGui/qguiapplication.h> @@ -205,7 +206,7 @@ QColor qt_color_from_string(const QV4::Value &name) return QColor(); } -static int qParseFontSizeFromToken(const QString &fontSizeToken, bool &ok) +static int qParseFontSizeFromToken(const QStringRef &fontSizeToken, bool &ok) { ok = false; float size = fontSizeToken.trimmed().toFloat(&ok); @@ -221,11 +222,11 @@ static int qParseFontSizeFromToken(const QString &fontSizeToken, bool &ok) \c true if successful. If the font size is invalid, \c false is returned and a warning is printed. */ -static bool qSetFontSizeFromToken(QFont &font, const QString &fontSizeToken) +static bool qSetFontSizeFromToken(QFont &font, const QStringRef &fontSizeToken) { - const QString trimmedToken = fontSizeToken.trimmed(); - const QString unitStr = trimmedToken.right(2); - const QString value = trimmedToken.left(trimmedToken.size() - 2); + const QStringRef trimmedToken = fontSizeToken.trimmed(); + const QStringRef unitStr = trimmedToken.right(2); + const QStringRef value = trimmedToken.left(trimmedToken.size() - 2); bool ok = false; int size = 0; if (unitStr == QLatin1String("px")) { @@ -251,7 +252,7 @@ static bool qSetFontSizeFromToken(QFont &font, const QString &fontSizeToken) each family is separated by spaces. Families with spaces in their name must be quoted. */ -static QStringList qExtractFontFamiliesFromString(const QString &fontFamiliesString) +static QStringList qExtractFontFamiliesFromString(const QStringRef &fontFamiliesString) { QStringList extractedFamilies; int quoteIndex = -1; @@ -264,7 +265,7 @@ static QStringList qExtractFontFamiliesFromString(const QString &fontFamiliesStr } else { if (ch == fontFamiliesString.at(quoteIndex)) { // Found the matching quote. +1/-1 because we don't want the quote as part of the name. - const QString family = fontFamiliesString.mid(quoteIndex + 1, index - quoteIndex - 1); + const QString family = fontFamiliesString.mid(quoteIndex + 1, index - quoteIndex - 1).toString(); extractedFamilies.push_back(family); currentFamily.clear(); quoteIndex = -1; @@ -395,16 +396,17 @@ static QFont qt_font_from_string(const QString& fontString, const QFont ¤t fontSizeEnd += 3; QFont newFont; - if (!qSetFontSizeFromToken(newFont, fontString.mid(fontSizeStart, fontSizeEnd - fontSizeStart))) + if (!qSetFontSizeFromToken(newFont, fontString.midRef(fontSizeStart, fontSizeEnd - fontSizeStart))) return currentFont; // We don't want to parse the size twice, so remove it now. QString remainingFontString = fontString; remainingFontString.remove(fontSizeStart, fontSizeEnd - fontSizeStart); + QStringRef remainingFontStringRef(&remainingFontString); // Next, we have to take any font families out, as QString::split() will ruin quoted family names. - const QString fontFamiliesString = remainingFontString.mid(fontSizeStart); - remainingFontString.chop(remainingFontString.length() - fontSizeStart); + const QStringRef fontFamiliesString = remainingFontStringRef.mid(fontSizeStart); + remainingFontStringRef.truncate(fontSizeStart); QStringList fontFamilies = qExtractFontFamiliesFromString(fontFamiliesString); if (fontFamilies.isEmpty()) { return currentFont; @@ -413,16 +415,16 @@ static QFont qt_font_from_string(const QString& fontString, const QFont ¤t return currentFont; // Now that we've removed the messy parts, we can split the font string on spaces. - const QString trimmedTokensStr = remainingFontString.trimmed(); + const QStringRef trimmedTokensStr = remainingFontStringRef.trimmed(); if (trimmedTokensStr.isEmpty()) { // No optional properties. return newFont; } - const QStringList tokens = trimmedTokensStr.split(QLatin1Char(' ')); + const auto tokens = trimmedTokensStr.split(QLatin1Char(' ')); int usedTokens = NoTokens; // Optional properties can be in any order, but font-size and font-family must be last. - for (const QString &token : tokens) { + for (const QStringRef &token : tokens) { if (token.compare(QLatin1String("normal")) == 0) { if (!(usedTokens & FontStyle) || !(usedTokens & FontVariant) || !(usedTokens & FontWeight)) { // Could be font-style, font-variant or font-weight. @@ -943,7 +945,7 @@ static QV4::ReturnedValue qt_create_image_data(qreal w, qreal h, QV4::ExecutionE pixelData->d()->image = QImage(w, h, QImage::Format_ARGB32); pixelData->d()->image.fill(0x00000000); } else { - Q_ASSERT(image.width() == int(w) && image.height() == int(h)); + Q_ASSERT(image.width() == qRound(w) && image.height() == qRound(h)); pixelData->d()->image = image.format() == QImage::Format_ARGB32 ? image : image.convertToFormat(QImage::Format_ARGB32); } @@ -1263,7 +1265,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_globalAlpha(QV4::CallContext *c double globalAlpha = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan(); - if (!qIsFinite(globalAlpha)) + if (!qt_is_finite(globalAlpha)) return QV4::Encode::undefined(); if (globalAlpha >= 0.0 && globalAlpha <= 1.0 && r->d()->context->state.globalAlpha != globalAlpha) { @@ -1547,10 +1549,10 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createLinearGradient(QV4:: qreal x1 = ctx->args()[2].toNumber(); qreal y1 = ctx->args()[3].toNumber(); - if (!qIsFinite(x0) - || !qIsFinite(y0) - || !qIsFinite(x1) - || !qIsFinite(y1)) { + if (!qt_is_finite(x0) + || !qt_is_finite(y0) + || !qt_is_finite(x1) + || !qt_is_finite(y1)) { V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createLinearGradient(): Incorrect arguments") } QQuickContext2DEngineData *ed = engineData(scope.engine); @@ -1592,12 +1594,12 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createRadialGradient(QV4:: qreal y1 = ctx->args()[4].toNumber(); qreal r1 = ctx->args()[5].toNumber(); - if (!qIsFinite(x0) - || !qIsFinite(y0) - || !qIsFinite(x1) - || !qIsFinite(r0) - || !qIsFinite(r1) - || !qIsFinite(y1)) { + if (!qt_is_finite(x0) + || !qt_is_finite(y0) + || !qt_is_finite(x1) + || !qt_is_finite(r0) + || !qt_is_finite(r1) + || !qt_is_finite(y1)) { V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createRadialGradient(): Incorrect arguments") } @@ -1639,11 +1641,11 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createConicalGradient(QV4: qreal x = ctx->args()[0].toNumber(); qreal y = ctx->args()[1].toNumber(); qreal angle = DEGREES(ctx->args()[2].toNumber()); - if (!qIsFinite(x) || !qIsFinite(y)) { + if (!qt_is_finite(x) || !qt_is_finite(y)) { V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createConicalGradient(): Incorrect arguments"); } - if (!qIsFinite(angle)) { + if (!qt_is_finite(angle)) { V4THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createConicalGradient(): Incorrect arguments"); } @@ -1894,7 +1896,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_lineWidth(QV4::CallContext *ctx qreal w = ctx->argc() ? ctx->args()[0].toNumber() : -1; - if (w > 0 && qIsFinite(w) && w != r->d()->context->state.lineWidth) { + if (w > 0 && qt_is_finite(w) && w != r->d()->context->state.lineWidth) { r->d()->context->state.lineWidth = w; r->d()->context->buffer()->setLineWidth(w); } @@ -1923,7 +1925,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_miterLimit(QV4::CallContext *ct qreal ml = ctx->argc() ? ctx->args()[0].toNumber() : -1; - if (ml > 0 && qIsFinite(ml) && ml != r->d()->context->state.miterLimit) { + if (ml > 0 && qt_is_finite(ml) && ml != r->d()->context->state.miterLimit) { r->d()->context->state.miterLimit = ml; r->d()->context->buffer()->setMiterLimit(ml); } @@ -1952,7 +1954,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_shadowBlur(QV4::CallContext *ct qreal blur = ctx->argc() ? ctx->args()[0].toNumber() : -1; - if (blur > 0 && qIsFinite(blur) && blur != r->d()->context->state.shadowBlur) { + if (blur > 0 && qt_is_finite(blur) && blur != r->d()->context->state.shadowBlur) { r->d()->context->state.shadowBlur = blur; r->d()->context->buffer()->setShadowBlur(blur); } @@ -2012,7 +2014,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_shadowOffsetX(QV4::CallContext CHECK_CONTEXT_SETTER(r) qreal offsetX = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan(); - if (qIsFinite(offsetX) && offsetX != r->d()->context->state.shadowOffsetX) { + if (qt_is_finite(offsetX) && offsetX != r->d()->context->state.shadowOffsetX) { r->d()->context->state.shadowOffsetX = offsetX; r->d()->context->buffer()->setShadowOffsetX(offsetX); } @@ -2040,7 +2042,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_shadowOffsetY(QV4::CallContext CHECK_CONTEXT_SETTER(r) qreal offsetY = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan(); - if (qIsFinite(offsetY) && offsetY != r->d()->context->state.shadowOffsetY) { + if (qt_is_finite(offsetY) && offsetY != r->d()->context->state.shadowOffsetY) { r->d()->context->state.shadowOffsetY = offsetY; r->d()->context->buffer()->setShadowOffsetY(offsetY); } @@ -2170,7 +2172,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_arc(QV4::CallContext *ctx) qreal radius = ctx->args()[2].toNumber(); - if (qIsFinite(radius) && radius < 0) + if (qt_is_finite(radius) && radius < 0) V4THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius"); r->d()->context->arc(ctx->args()[0].toNumber(), @@ -2216,7 +2218,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_arcTo(QV4::CallContext *ct if (ctx->argc() >= 5) { qreal radius = ctx->args()[4].toNumber(); - if (qIsFinite(radius) && radius < 0) + if (qt_is_finite(radius) && radius < 0) V4THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius"); r->d()->context->arcTo(ctx->args()[0].toNumber(), @@ -2279,7 +2281,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_bezierCurveTo(QV4::CallCon qreal x = ctx->args()[4].toNumber(); qreal y = ctx->args()[5].toNumber(); - if (!qIsFinite(cp1x) || !qIsFinite(cp1y) || !qIsFinite(cp2x) || !qIsFinite(cp2y) || !qIsFinite(x) || !qIsFinite(y)) + if (!qt_is_finite(cp1x) || !qt_is_finite(cp1y) || !qt_is_finite(cp2x) || !qt_is_finite(cp2y) || !qt_is_finite(x) || !qt_is_finite(y)) return ctx->thisObject().asReturnedValue(); r->d()->context->bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y); @@ -2375,7 +2377,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_lineTo(QV4::CallContext *c qreal x = ctx->args()[0].toNumber(); qreal y = ctx->args()[1].toNumber(); - if (!qIsFinite(x) || !qIsFinite(y)) + if (!qt_is_finite(x) || !qt_is_finite(y)) return ctx->thisObject().asReturnedValue(); r->d()->context->lineTo(x, y); @@ -2399,7 +2401,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_moveTo(QV4::CallContext *c qreal x = ctx->args()[0].toNumber(); qreal y = ctx->args()[1].toNumber(); - if (!qIsFinite(x) || !qIsFinite(y)) + if (!qt_is_finite(x) || !qt_is_finite(y)) return ctx->thisObject().asReturnedValue(); r->d()->context->moveTo(x, y); } @@ -2425,7 +2427,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_quadraticCurveTo(QV4::Call qreal x = ctx->args()[2].toNumber(); qreal y = ctx->args()[3].toNumber(); - if (!qIsFinite(cpx) || !qIsFinite(cpy) || !qIsFinite(x) || !qIsFinite(y)) + if (!qt_is_finite(cpx) || !qt_is_finite(cpy) || !qt_is_finite(x) || !qt_is_finite(y)) return ctx->thisObject().asReturnedValue(); r->d()->context->quadraticCurveTo(cpx, cpy, x, y); @@ -2509,7 +2511,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_text(QV4::CallContext *ctx qreal x = ctx->args()[1].toNumber(); qreal y = ctx->args()[2].toNumber(); - if (!qIsFinite(x) || !qIsFinite(y)) + if (!qt_is_finite(x) || !qt_is_finite(y)) return ctx->thisObject().asReturnedValue(); r->d()->context->text(ctx->args()[0].toQStringNoThrow(), x, y); } @@ -2774,7 +2776,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_fillText(QV4::CallContext if (ctx->argc() >= 3) { qreal x = ctx->args()[1].toNumber(); qreal y = ctx->args()[2].toNumber(); - if (!qIsFinite(x) || !qIsFinite(y)) + if (!qt_is_finite(x) || !qt_is_finite(y)) return ctx->thisObject().asReturnedValue(); QPainterPath textPath = r->d()->context->createTextGlyphs(x, y, ctx->args()[0].toQStringNoThrow()); r->d()->context->buffer()->fill(textPath); @@ -2973,14 +2975,14 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext return ctx->thisObject().asReturnedValue(); } - if (!qIsFinite(sx) - || !qIsFinite(sy) - || !qIsFinite(sw) - || !qIsFinite(sh) - || !qIsFinite(dx) - || !qIsFinite(dy) - || !qIsFinite(dw) - || !qIsFinite(dh)) + if (!qt_is_finite(sx) + || !qt_is_finite(sy) + || !qt_is_finite(sw) + || !qt_is_finite(sh) + || !qt_is_finite(dx) + || !qt_is_finite(dy) + || !qt_is_finite(dw) + || !qt_is_finite(dh)) return ctx->thisObject().asReturnedValue(); if (sx < 0 @@ -3201,7 +3203,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createImageData(QV4::CallC qreal w = ctx->args()[0].toNumber(); qreal h = ctx->args()[1].toNumber(); - if (!qIsFinite(w) || !qIsFinite(h)) + if (!qt_is_finite(w) || !qt_is_finite(h)) V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createImageData(): invalid arguments"); if (w > 0 && h > 0) @@ -3227,7 +3229,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_getImageData(QV4::CallCont qreal y = ctx->args()[1].toNumber(); qreal w = ctx->args()[2].toNumber(); qreal h = ctx->args()[3].toNumber(); - if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h)) + if (!qt_is_finite(x) || !qt_is_finite(y) || !qt_is_finite(w) || !qt_is_finite(h)) V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "getImageData(): Invalid arguments"); if (w <= 0 || h <= 0) @@ -3259,7 +3261,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_putImageData(QV4::CallCont qreal dy = ctx->args()[2].toNumber(); qreal w, h, dirtyX, dirtyY, dirtyWidth, dirtyHeight; - if (!qIsFinite(dx) || !qIsFinite(dy)) + if (!qt_is_finite(dx) || !qt_is_finite(dy)) V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "putImageData() : Invalid arguments"); QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, arg0); @@ -3277,7 +3279,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_putImageData(QV4::CallCont dirtyWidth = ctx->args()[5].toNumber(); dirtyHeight = ctx->args()[6].toNumber(); - if (!qIsFinite(dirtyX) || !qIsFinite(dirtyY) || !qIsFinite(dirtyWidth) || !qIsFinite(dirtyHeight)) + if (!qt_is_finite(dirtyX) || !qt_is_finite(dirtyY) || !qt_is_finite(dirtyWidth) || !qt_is_finite(dirtyHeight)) V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "putImageData() : Invalid arguments"); @@ -3364,7 +3366,7 @@ QV4::ReturnedValue QQuickContext2DStyle::gradient_proto_addColorStop(QV4::CallCo } else { color = qt_color_from_string(ctx->args()[1]); } - if (pos < 0.0 || pos > 1.0 || !qIsFinite(pos)) { + if (pos < 0.0 || pos > 1.0 || !qt_is_finite(pos)) { V4THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "CanvasGradient: parameter offset out of range"); } @@ -3384,7 +3386,7 @@ void QQuickContext2D::scale(qreal x, qreal y) if (!state.invertibleCTM) return; - if (!qIsFinite(x) || !qIsFinite(y)) + if (!qt_is_finite(x) || !qt_is_finite(y)) return; QTransform newTransform = state.matrix; @@ -3405,7 +3407,7 @@ void QQuickContext2D::rotate(qreal angle) if (!state.invertibleCTM) return; - if (!qIsFinite(angle)) + if (!qt_is_finite(angle)) return; QTransform newTransform =state.matrix; @@ -3426,7 +3428,7 @@ void QQuickContext2D::shear(qreal h, qreal v) if (!state.invertibleCTM) return; - if (!qIsFinite(h) || !qIsFinite(v)) + if (!qt_is_finite(h) || !qt_is_finite(v)) return ; QTransform newTransform = state.matrix; @@ -3447,7 +3449,7 @@ void QQuickContext2D::translate(qreal x, qreal y) if (!state.invertibleCTM) return; - if (!qIsFinite(x) || !qIsFinite(y)) + if (!qt_is_finite(x) || !qt_is_finite(y)) return ; QTransform newTransform = state.matrix; @@ -3468,7 +3470,7 @@ void QQuickContext2D::transform(qreal a, qreal b, qreal c, qreal d, qreal e, qre if (!state.invertibleCTM) return; - if (!qIsFinite(a) || !qIsFinite(b) || !qIsFinite(c) || !qIsFinite(d) || !qIsFinite(e) || !qIsFinite(f)) + if (!qt_is_finite(a) || !qt_is_finite(b) || !qt_is_finite(c) || !qt_is_finite(d) || !qt_is_finite(e) || !qt_is_finite(f)) return; QTransform transform(a, b, c, d, e, f); @@ -3485,7 +3487,7 @@ void QQuickContext2D::transform(qreal a, qreal b, qreal c, qreal d, qreal e, qre void QQuickContext2D::setTransform(qreal a, qreal b, qreal c, qreal d, qreal e, qreal f) { - if (!qIsFinite(a) || !qIsFinite(b) || !qIsFinite(c) || !qIsFinite(d) || !qIsFinite(e) || !qIsFinite(f)) + if (!qt_is_finite(a) || !qt_is_finite(b) || !qt_is_finite(c) || !qt_is_finite(d) || !qt_is_finite(e) || !qt_is_finite(f)) return; QTransform ctm = state.matrix; @@ -3542,7 +3544,7 @@ void QQuickContext2D::fillRect(qreal x, qreal y, qreal w, qreal h) if (!state.invertibleCTM) return; - if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h)) + if (!qt_is_finite(x) || !qt_is_finite(y) || !qt_is_finite(w) || !qt_is_finite(h)) return; buffer()->fillRect(QRectF(x, y, w, h)); @@ -3553,7 +3555,7 @@ void QQuickContext2D::strokeRect(qreal x, qreal y, qreal w, qreal h) if (!state.invertibleCTM) return; - if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h)) + if (!qt_is_finite(x) || !qt_is_finite(y) || !qt_is_finite(w) || !qt_is_finite(h)) return; buffer()->strokeRect(QRectF(x, y, w, h)); @@ -3564,7 +3566,7 @@ void QQuickContext2D::clearRect(qreal x, qreal y, qreal w, qreal h) if (!state.invertibleCTM) return; - if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h)) + if (!qt_is_finite(x) || !qt_is_finite(y) || !qt_is_finite(w) || !qt_is_finite(h)) return; buffer()->clearRect(QRectF(x, y, w, h)); @@ -3575,7 +3577,7 @@ void QQuickContext2D::drawText(const QString& text, qreal x, qreal y, bool fill) if (!state.invertibleCTM) return; - if (!qIsFinite(x) || !qIsFinite(y)) + if (!qt_is_finite(x) || !qt_is_finite(y)) return; QPainterPath textPath = createTextGlyphs(x, y, text); @@ -3721,7 +3723,7 @@ void QQuickContext2D::arcTo(qreal x1, qreal y1, if (!state.invertibleCTM) return; - if (!qIsFinite(x1) || !qIsFinite(y1) || !qIsFinite(x2) || !qIsFinite(y2) || !qIsFinite(radius)) + if (!qt_is_finite(x1) || !qt_is_finite(y1) || !qt_is_finite(x2) || !qt_is_finite(y2) || !qt_is_finite(radius)) return; QPointF st(x1, y1); @@ -3739,7 +3741,7 @@ void QQuickContext2D::rect(qreal x, qreal y, qreal w, qreal h) { if (!state.invertibleCTM) return; - if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h)) + if (!qt_is_finite(x) || !qt_is_finite(y) || !qt_is_finite(w) || !qt_is_finite(h)) return; if (!w && !h) { @@ -3756,7 +3758,7 @@ void QQuickContext2D::roundedRect(qreal x, qreal y, if (!state.invertibleCTM) return; - if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h) || !qIsFinite(xr) || !qIsFinite(yr)) + if (!qt_is_finite(x) || !qt_is_finite(y) || !qt_is_finite(w) || !qt_is_finite(h) || !qt_is_finite(xr) || !qt_is_finite(yr)) return; if (!w && !h) { @@ -3772,7 +3774,7 @@ void QQuickContext2D::ellipse(qreal x, qreal y, if (!state.invertibleCTM) return; - if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h)) + if (!qt_is_finite(x) || !qt_is_finite(y) || !qt_is_finite(w) || !qt_is_finite(h)) return; if (!w && !h) { @@ -3798,7 +3800,7 @@ void QQuickContext2D::arc(qreal xc, qreal yc, qreal radius, qreal sar, qreal ear if (!state.invertibleCTM) return; - if (!qIsFinite(xc) || !qIsFinite(yc) || !qIsFinite(sar) || !qIsFinite(ear) || !qIsFinite(radius)) + if (!qt_is_finite(xc) || !qt_is_finite(yc) || !qt_is_finite(sar) || !qt_is_finite(ear) || !qt_is_finite(radius)) return; if (sar == ear) @@ -3937,13 +3939,13 @@ bool QQuickContext2D::isPointInPath(qreal x, qreal y) const if (!m_path.elementCount()) return false; - if (!qIsFinite(x) || !qIsFinite(y)) + if (!qt_is_finite(x) || !qt_is_finite(y)) return false; QPointF point(x, y); QTransform ctm = state.matrix; QPointF p = ctm.inverted().map(point); - if (!qIsFinite(p.x()) || !qIsFinite(p.y())) + if (!qt_is_finite(p.x()) || !qt_is_finite(p.y())) return false; const_cast<QQuickContext2D *>(this)->m_path.setFillRule(state.fillRule); diff --git a/src/quick/items/qquickanchors.cpp b/src/quick/items/qquickanchors.cpp index d87669df56..4cbd41106e 100644 --- a/src/quick/items/qquickanchors.cpp +++ b/src/quick/items/qquickanchors.cpp @@ -39,19 +39,48 @@ #include "qquickanchors_p_p.h" -#include "qquickitem.h" #include "qquickitem_p.h" #include <qqmlinfo.h> QT_BEGIN_NAMESPACE +static Q_ALWAYS_INLINE QQuickItem *readParentItem(const QQuickItem *item) +{ + return QQuickItemPrivate::get(item)->parentItem; +} + +static Q_ALWAYS_INLINE qreal readX(const QQuickItem *item) +{ + return QQuickItemPrivate::get(item)->x; +} + +static Q_ALWAYS_INLINE qreal readY(const QQuickItem *item) +{ + return QQuickItemPrivate::get(item)->y; +} + +static Q_ALWAYS_INLINE qreal readWidth(const QQuickItem *item) +{ + return QQuickItemPrivate::get(item)->width; +} + +static Q_ALWAYS_INLINE qreal readHeight(const QQuickItem *item) +{ + return QQuickItemPrivate::get(item)->height; +} + +static Q_ALWAYS_INLINE qreal readBaselineOffset(const QQuickItem *item) +{ + return QQuickItemPrivate::get(item)->baselineOffset; +} + //TODO: should we cache relationships, so we don't have to check each time (parent-child or sibling)? //TODO: support non-parent, non-sibling (need to find lowest common ancestor) -static inline qreal hcenter(QQuickItem const *item) +static inline qreal hcenter(const QQuickItem *item) { - qreal width = item->width(); + qreal width = readWidth(item); if (QQuickAnchors *anchors = QQuickItemPrivate::get(item)->_anchors) { if (!QQuickAnchorsPrivate::get(anchors)->centerAligned) return width / 2; @@ -63,9 +92,9 @@ static inline qreal hcenter(QQuickItem const *item) return width / 2; } -static inline qreal vcenter(QQuickItem const *item) +static inline qreal vcenter(const QQuickItem *item) { - qreal height = item->height(); + qreal height = readHeight(item); if (QQuickAnchors *anchors = QQuickItemPrivate::get(item)->_anchors) { if (!QQuickAnchorsPrivate::get(anchors)->centerAligned) return height / 2; @@ -78,30 +107,30 @@ static inline qreal vcenter(QQuickItem const *item) } //local position -static qreal position(QQuickItem const *item, QQuickAnchorLine::AnchorLine anchorLine) +static inline qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine) { qreal ret = 0.0; switch (anchorLine) { - case QQuickAnchorLine::Left: - ret = item->x(); + case QQuickAnchors::LeftAnchor: + ret = readX(item); break; - case QQuickAnchorLine::Right: - ret = item->x() + item->width(); + case QQuickAnchors::RightAnchor: + ret = readX(item) + readWidth(item); break; - case QQuickAnchorLine::Top: - ret = item->y(); + case QQuickAnchors::TopAnchor: + ret = readY(item); break; - case QQuickAnchorLine::Bottom: - ret = item->y() + item->height(); + case QQuickAnchors::BottomAnchor: + ret = readY(item) + readHeight(item); break; - case QQuickAnchorLine::HCenter: - ret = item->x() + hcenter(item); + case QQuickAnchors::HCenterAnchor: + ret = readX(item) + hcenter(item); break; - case QQuickAnchorLine::VCenter: - ret = item->y() + vcenter(item); + case QQuickAnchors::VCenterAnchor: + ret = readY(item) + vcenter(item); break; - case QQuickAnchorLine::Baseline: - ret = item->y() + item->baselineOffset(); + case QQuickAnchors::BaselineAnchor: + ret = readY(item) + readBaselineOffset(item); break; default: break; @@ -111,30 +140,30 @@ static qreal position(QQuickItem const *item, QQuickAnchorLine::AnchorLine ancho } //position when origin is 0,0 -static qreal adjustedPosition(QQuickItem *item, QQuickAnchorLine::AnchorLine anchorLine) +static inline qreal adjustedPosition(QQuickItem *item, QQuickAnchors::Anchor anchorLine) { qreal ret = 0.0; switch (anchorLine) { - case QQuickAnchorLine::Left: + case QQuickAnchors::LeftAnchor: ret = 0.0; break; - case QQuickAnchorLine::Right: - ret = item->width(); + case QQuickAnchors::RightAnchor: + ret = readWidth(item); break; - case QQuickAnchorLine::Top: + case QQuickAnchors::TopAnchor: ret = 0.0; break; - case QQuickAnchorLine::Bottom: - ret = item->height(); + case QQuickAnchors::BottomAnchor: + ret = readHeight(item); break; - case QQuickAnchorLine::HCenter: + case QQuickAnchors::HCenterAnchor: ret = hcenter(item); break; - case QQuickAnchorLine::VCenter: + case QQuickAnchors::VCenterAnchor: ret = vcenter(item); break; - case QQuickAnchorLine::Baseline: - ret = item->baselineOffset(); + case QQuickAnchors::BaselineAnchor: + ret = readBaselineOffset(item); break; default: break; @@ -154,13 +183,13 @@ QQuickAnchors::~QQuickAnchors() d->inDestructor = true; d->remDepend(d->fill); d->remDepend(d->centerIn); - d->remDepend(d->left.item); - d->remDepend(d->right.item); - d->remDepend(d->top.item); - d->remDepend(d->bottom.item); - d->remDepend(d->vCenter.item); - d->remDepend(d->hCenter.item); - d->remDepend(d->baseline.item); + d->remDepend(d->leftAnchorItem); + d->remDepend(d->rightAnchorItem); + d->remDepend(d->topAnchorItem); + d->remDepend(d->bottomAnchorItem); + d->remDepend(d->vCenterAnchorItem); + d->remDepend(d->hCenterAnchorItem); + d->remDepend(d->baselineAnchorItem); } void QQuickAnchorsPrivate::fillChanged() @@ -174,12 +203,13 @@ void QQuickAnchorsPrivate::fillChanged() qreal horizontalMargin = q->mirrored() ? rightMargin : leftMargin; - if (fill == item->parentItem()) { //child-parent + if (fill == readParentItem(item)) { //child-parent setItemPos(QPointF(horizontalMargin, topMargin)); - } else if (fill->parentItem() == item->parentItem()) { //siblings - setItemPos(QPointF(fill->x()+horizontalMargin, fill->y()+topMargin)); + } else if (readParentItem(fill) == readParentItem(item)) { //siblings + setItemPos(QPointF(readX(fill)+horizontalMargin, readY(fill) + topMargin)); } - setItemSize(QSizeF(fill->width()-leftMargin-rightMargin, fill->height()-topMargin-bottomMargin)); + setItemSize(QSizeF(readWidth(fill) - leftMargin - rightMargin, + readHeight(fill) - topMargin - bottomMargin)); --updatingFill; } else { @@ -199,12 +229,12 @@ void QQuickAnchorsPrivate::centerInChanged() ++updatingCenterIn; qreal effectiveHCenterOffset = q->mirrored() ? -hCenterOffset : hCenterOffset; - if (centerIn == item->parentItem()) { - QPointF p(hcenter(item->parentItem()) - hcenter(item) + effectiveHCenterOffset, - vcenter(item->parentItem()) - vcenter(item) + vCenterOffset); + if (centerIn == readParentItem(item)) { + QPointF p(hcenter(readParentItem(item)) - hcenter(item) + effectiveHCenterOffset, + vcenter(readParentItem(item)) - vcenter(item) + vCenterOffset); setItemPos(p); - } else if (centerIn->parentItem() == item->parentItem()) { + } else if (readParentItem(centerIn) == readParentItem(item)) { QPointF p(centerIn->x() + hcenter(centerIn) - hcenter(item) + effectiveHCenterOffset, centerIn->y() + vcenter(centerIn) - vcenter(item) + vCenterOffset); setItemPos(p); @@ -225,32 +255,32 @@ void QQuickAnchorsPrivate::clearItem(QQuickItem *item) fill = 0; if (centerIn == item) centerIn = 0; - if (left.item == item) { - left.item = 0; + if (leftAnchorItem == item) { + leftAnchorItem = 0; usedAnchors &= ~QQuickAnchors::LeftAnchor; } - if (right.item == item) { - right.item = 0; + if (rightAnchorItem == item) { + rightAnchorItem = 0; usedAnchors &= ~QQuickAnchors::RightAnchor; } - if (top.item == item) { - top.item = 0; + if (topAnchorItem == item) { + topAnchorItem = 0; usedAnchors &= ~QQuickAnchors::TopAnchor; } - if (bottom.item == item) { - bottom.item = 0; + if (bottomAnchorItem == item) { + bottomAnchorItem = 0; usedAnchors &= ~QQuickAnchors::BottomAnchor; } - if (vCenter.item == item) { - vCenter.item = 0; + if (vCenterAnchorItem == item) { + vCenterAnchorItem = 0; usedAnchors &= ~QQuickAnchors::VCenterAnchor; } - if (hCenter.item == item) { - hCenter.item = 0; + if (hCenterAnchorItem == item) { + hCenterAnchorItem = 0; usedAnchors &= ~QQuickAnchors::HCenterAnchor; } - if (baseline.item == item) { - baseline.item = 0; + if (baselineAnchorItem == item) { + baselineAnchorItem = 0; usedAnchors &= ~QQuickAnchors::BaselineAnchor; } } @@ -263,7 +293,7 @@ int QQuickAnchorsPrivate::calculateDependency(QQuickItem *controlItem) return dependency; if (fill == controlItem) { - if (controlItem == item->parentItem()) + if (controlItem == readParentItem(item)) dependency |= QQuickItemPrivate::SizeChange; else //sibling dependency |= QQuickItemPrivate::GeometryChange; @@ -271,27 +301,27 @@ int QQuickAnchorsPrivate::calculateDependency(QQuickItem *controlItem) } if (centerIn == controlItem) { - if (controlItem == item->parentItem()) + if (controlItem == readParentItem(item)) dependency |= QQuickItemPrivate::SizeChange; else //sibling dependency |= QQuickItemPrivate::GeometryChange; return dependency; //exit early } - if ((usedAnchors & QQuickAnchors::LeftAnchor && left.item == controlItem) || - (usedAnchors & QQuickAnchors::RightAnchor && right.item == controlItem) || - (usedAnchors & QQuickAnchors::HCenterAnchor && hCenter.item == controlItem)) { - if (controlItem == item->parentItem()) + if ((usedAnchors & QQuickAnchors::LeftAnchor && leftAnchorItem == controlItem) || + (usedAnchors & QQuickAnchors::RightAnchor && rightAnchorItem == controlItem) || + (usedAnchors & QQuickAnchors::HCenterAnchor && hCenterAnchorItem == controlItem)) { + if (controlItem == readParentItem(item)) dependency |= QQuickItemPrivate::WidthChange; else //sibling dependency |= QFlags<QQuickItemPrivate::GeometryChangeType>(QQuickItemPrivate::XChange | QQuickItemPrivate::WidthChange); } - if ((usedAnchors & QQuickAnchors::TopAnchor && top.item == controlItem) || - (usedAnchors & QQuickAnchors::BottomAnchor && bottom.item == controlItem) || - (usedAnchors & QQuickAnchors::VCenterAnchor && vCenter.item == controlItem) || - (usedAnchors & QQuickAnchors::BaselineAnchor && baseline.item == controlItem)) { - if (controlItem == item->parentItem()) + if ((usedAnchors & QQuickAnchors::TopAnchor && topAnchorItem == controlItem) || + (usedAnchors & QQuickAnchors::BottomAnchor && bottomAnchorItem == controlItem) || + (usedAnchors & QQuickAnchors::VCenterAnchor && vCenterAnchorItem == controlItem) || + (usedAnchors & QQuickAnchors::BaselineAnchor && baselineAnchorItem == controlItem)) { + if (controlItem == readParentItem(item)) dependency |= QQuickItemPrivate::HeightChange; else //sibling dependency |= QFlags<QQuickItemPrivate::GeometryChangeType>(QQuickItemPrivate::YChange | QQuickItemPrivate::HeightChange); @@ -422,13 +452,13 @@ void QQuickAnchorsPrivate::updateOnComplete() QQuickItem *dependencies[9]; dependencies[0] = fill; dependencies[1] = centerIn; - dependencies[2] = left.item; - dependencies[3] = right.item; - dependencies[4] = hCenter.item; - dependencies[5] = top.item; - dependencies[6] = bottom.item; - dependencies[7] = vCenter.item; - dependencies[8] = baseline.item; + dependencies[2] = leftAnchorItem; + dependencies[3] = rightAnchorItem; + dependencies[4] = hCenterAnchorItem; + dependencies[5] = topAnchorItem; + dependencies[6] = bottomAnchorItem; + dependencies[7] = vCenterAnchorItem; + dependencies[8] = baselineAnchorItem; std::sort(dependencies, dependencies + 9); @@ -447,22 +477,38 @@ void QQuickAnchorsPrivate::updateOnComplete() void QQuickAnchorsPrivate::update() { - fillChanged(); - centerInChanged(); - if (usedAnchors & QQuickAnchorLine::Horizontal_Mask) - updateHorizontalAnchors(); - if (usedAnchors & QQuickAnchorLine::Vertical_Mask) - updateVerticalAnchors(); + if (!isItemComplete()) + return; + + if (fill) { + fillChanged(); + } else if (centerIn) { + centerInChanged(); + } else { + if (usedAnchors & QQuickAnchors::Horizontal_Mask) + updateHorizontalAnchors(); + if (usedAnchors & QQuickAnchors::Vertical_Mask) + updateVerticalAnchors(); + } } void QQuickAnchorsPrivate::itemGeometryChanged(QQuickItem *, const QRectF &newG, const QRectF &oldG) { - fillChanged(); - centerInChanged(); - if ((usedAnchors & QQuickAnchorLine::Horizontal_Mask) && (newG.x() != oldG.x() || newG.width() != oldG.width())) - updateHorizontalAnchors(); - if ((usedAnchors & QQuickAnchorLine::Vertical_Mask) && (newG.y() != oldG.y() || newG.height() != oldG.height())) - updateVerticalAnchors(); + if (!isItemComplete()) + return; + + if (fill) { + fillChanged(); + } else if (centerIn) { + centerInChanged(); + } else { + if ((usedAnchors & QQuickAnchors::Horizontal_Mask) + && (newG.x() != oldG.x() || newG.width() != oldG.width())) + updateHorizontalAnchors(); + if ((usedAnchors & QQuickAnchors::Vertical_Mask) + && (newG.y() != oldG.y() || newG.height() != oldG.height())) + updateVerticalAnchors(); + } } QQuickItem *QQuickAnchors::fill() const @@ -484,7 +530,7 @@ void QQuickAnchors::setFill(QQuickItem *f) emit fillChanged(); return; } - if (f != d->item->parentItem() && f->parentItem() != d->item->parentItem()){ + if (f != readParentItem(d->item) && readParentItem(f) != readParentItem(d->item)){ qmlInfo(d->item) << tr("Cannot anchor to an item that isn't a parent or sibling."); return; } @@ -520,7 +566,7 @@ void QQuickAnchors::setCenterIn(QQuickItem* c) emit centerInChanged(); return; } - if (c != d->item->parentItem() && c->parentItem() != d->item->parentItem()){ + if (c != readParentItem(d->item) && readParentItem(c) != readParentItem(d->item)){ qmlInfo(d->item) << tr("Cannot anchor to an item that isn't a parent or sibling."); return; } @@ -537,29 +583,31 @@ void QQuickAnchors::resetCenterIn() setCenterIn(0); } -bool QQuickAnchorsPrivate::calcStretch(const QQuickAnchorLine &edge1, - const QQuickAnchorLine &edge2, - qreal offset1, - qreal offset2, - QQuickAnchorLine::AnchorLine line, - qreal &stretch) +bool QQuickAnchorsPrivate::calcStretch(QQuickItem *edge1Item, + QQuickAnchors::Anchor edge1Line, + QQuickItem *edge2Item, + QQuickAnchors::Anchor edge2Line, + qreal offset1, + qreal offset2, + QQuickAnchors::Anchor line, + qreal &stretch) { - bool edge1IsParent = (edge1.item == item->parentItem()); - bool edge2IsParent = (edge2.item == item->parentItem()); - bool edge1IsSibling = (edge1.item->parentItem() == item->parentItem()); - bool edge2IsSibling = (edge2.item->parentItem() == item->parentItem()); + bool edge1IsParent = (edge1Item == readParentItem(item)); + bool edge2IsParent = (edge2Item == readParentItem(item)); + bool edge1IsSibling = (readParentItem(edge1Item) == readParentItem(item)); + bool edge2IsSibling = (readParentItem(edge2Item) == readParentItem(item)); bool invalid = false; if ((edge2IsParent && edge1IsParent) || (edge2IsSibling && edge1IsSibling)) { - stretch = (position(edge2.item, edge2.anchorLine) + offset2) - - (position(edge1.item, edge1.anchorLine) + offset1); + stretch = (position(edge2Item, edge2Line) + offset2) + - (position(edge1Item, edge1Line) + offset1); } else if (edge2IsParent && edge1IsSibling) { - stretch = (position(edge2.item, edge2.anchorLine) + offset2) - - (position(item->parentItem(), line) - + position(edge1.item, edge1.anchorLine) + offset1); + stretch = (position(edge2Item, edge2Line) + offset2) + - (position(readParentItem(item), line) + + position(edge1Item, edge1Line) + offset1); } else if (edge2IsSibling && edge1IsParent) { - stretch = (position(item->parentItem(), line) + position(edge2.item, edge2.anchorLine) + offset2) - - (position(edge1.item, edge1.anchorLine) + offset1); + stretch = (position(readParentItem(item), line) + position(edge2Item, edge2Line) + offset2) + - (position(edge1Item, edge1Line) + offset1); } else invalid = true; @@ -578,52 +626,60 @@ void QQuickAnchorsPrivate::updateVerticalAnchors() bool invalid = true; qreal height = 0.0; if (usedAnchors & QQuickAnchors::BottomAnchor) { - invalid = calcStretch(top, bottom, topMargin, -bottomMargin, QQuickAnchorLine::Top, height); + invalid = calcStretch(topAnchorItem, topAnchorLine, + bottomAnchorItem, bottomAnchorLine, + topMargin, -bottomMargin, QQuickAnchors::TopAnchor, height); } else if (usedAnchors & QQuickAnchors::VCenterAnchor) { - invalid = calcStretch(top, vCenter, topMargin, vCenterOffset, QQuickAnchorLine::Top, height); + invalid = calcStretch(topAnchorItem, topAnchorLine, + vCenterAnchorItem, vCenterAnchorLine, + topMargin, vCenterOffset, QQuickAnchors::TopAnchor, height); height *= 2; } if (!invalid) setItemHeight(height); //Handle top - if (top.item == item->parentItem()) { - setItemY(adjustedPosition(top.item, top.anchorLine) + topMargin); - } else if (top.item->parentItem() == item->parentItem()) { - setItemY(position(top.item, top.anchorLine) + topMargin); + if (topAnchorItem == readParentItem(item)) { + setItemY(adjustedPosition(topAnchorItem, topAnchorLine) + topMargin); + } else if (readParentItem(topAnchorItem) == readParentItem(item)) { + setItemY(position(topAnchorItem, topAnchorLine) + topMargin); } } else if (usedAnchors & QQuickAnchors::BottomAnchor) { //Handle stretching (top + bottom case is handled above) if (usedAnchors & QQuickAnchors::VCenterAnchor) { qreal height = 0.0; - bool invalid = calcStretch(vCenter, bottom, vCenterOffset, -bottomMargin, - QQuickAnchorLine::Top, height); + bool invalid = calcStretch(vCenterAnchorItem, vCenterAnchorLine, + bottomAnchorItem, bottomAnchorLine, + vCenterOffset, -bottomMargin, QQuickAnchors::TopAnchor, + height); if (!invalid) setItemHeight(height*2); } //Handle bottom - if (bottom.item == item->parentItem()) { - setItemY(adjustedPosition(bottom.item, bottom.anchorLine) - item->height() - bottomMargin); - } else if (bottom.item->parentItem() == item->parentItem()) { - setItemY(position(bottom.item, bottom.anchorLine) - item->height() - bottomMargin); + if (bottomAnchorItem == readParentItem(item)) { + setItemY(adjustedPosition(bottomAnchorItem, bottomAnchorLine) - readHeight(item) - bottomMargin); + } else if (readParentItem(bottomAnchorItem) == readParentItem(item)) { + setItemY(position(bottomAnchorItem, bottomAnchorLine) - readHeight(item) - bottomMargin); } } else if (usedAnchors & QQuickAnchors::VCenterAnchor) { //(stetching handled above) //Handle vCenter - if (vCenter.item == item->parentItem()) { - setItemY(adjustedPosition(vCenter.item, vCenter.anchorLine) + if (vCenterAnchorItem == readParentItem(item)) { + setItemY(adjustedPosition(vCenterAnchorItem, vCenterAnchorLine) - vcenter(item) + vCenterOffset); - } else if (vCenter.item->parentItem() == item->parentItem()) { - setItemY(position(vCenter.item, vCenter.anchorLine) - vcenter(item) + vCenterOffset); + } else if (readParentItem(vCenterAnchorItem) == readParentItem(item)) { + setItemY(position(vCenterAnchorItem, vCenterAnchorLine) - vcenter(item) + vCenterOffset); } } else if (usedAnchors & QQuickAnchors::BaselineAnchor) { //Handle baseline - if (baseline.item == item->parentItem()) { - setItemY(adjustedPosition(baseline.item, baseline.anchorLine) - item->baselineOffset() + baselineOffset); - } else if (baseline.item->parentItem() == item->parentItem()) { - setItemY(position(baseline.item, baseline.anchorLine) - item->baselineOffset() + baselineOffset); + if (baselineAnchorItem == readParentItem(item)) { + setItemY(adjustedPosition(baselineAnchorItem, baselineAnchorLine) + - readBaselineOffset(item) + baselineOffset); + } else if (readParentItem(baselineAnchorItem) == readParentItem(item)) { + setItemY(position(baselineAnchorItem, baselineAnchorLine) + - readBaselineOffset(item) + baselineOffset); } } --updatingVerticalAnchor; @@ -633,12 +689,12 @@ void QQuickAnchorsPrivate::updateVerticalAnchors() } } -inline QQuickAnchorLine::AnchorLine reverseAnchorLine(QQuickAnchorLine::AnchorLine anchorLine) +static inline QQuickAnchors::Anchor reverseAnchorLine(QQuickAnchors::Anchor anchorLine) { - if (anchorLine == QQuickAnchorLine::Left) { - return QQuickAnchorLine::Right; - } else if (anchorLine == QQuickAnchorLine::Right) { - return QQuickAnchorLine::Left; + if (anchorLine == QQuickAnchors::LeftAnchor) { + return QQuickAnchors::RightAnchor; + } else if (anchorLine == QQuickAnchors::RightAnchor) { + return QQuickAnchors::LeftAnchor; } else { return anchorLine; } @@ -653,26 +709,30 @@ void QQuickAnchorsPrivate::updateHorizontalAnchors() if (updatingHorizontalAnchor < 3) { ++updatingHorizontalAnchor; qreal effectiveRightMargin, effectiveLeftMargin, effectiveHorizontalCenterOffset; - QQuickAnchorLine effectiveLeft, effectiveRight, effectiveHorizontalCenter; + QQuickItem *effectiveLeftItem, *effectiveRightItem, *effectiveHorizontalCenterItem; + QQuickAnchors::Anchor effectiveLeftLine, effectiveRightLine, effectiveHorizontalCenterLine; QQuickAnchors::Anchor effectiveLeftAnchor, effectiveRightAnchor; if (q->mirrored()) { effectiveLeftAnchor = QQuickAnchors::RightAnchor; effectiveRightAnchor = QQuickAnchors::LeftAnchor; - effectiveLeft.item = right.item; - effectiveLeft.anchorLine = reverseAnchorLine(right.anchorLine); - effectiveRight.item = left.item; - effectiveRight.anchorLine = reverseAnchorLine(left.anchorLine); - effectiveHorizontalCenter.item = hCenter.item; - effectiveHorizontalCenter.anchorLine = reverseAnchorLine(hCenter.anchorLine); + effectiveLeftItem = rightAnchorItem; + effectiveLeftLine = reverseAnchorLine(rightAnchorLine); + effectiveRightItem = leftAnchorItem; + effectiveRightLine = reverseAnchorLine(leftAnchorLine); + effectiveHorizontalCenterItem = hCenterAnchorItem; + effectiveHorizontalCenterLine = reverseAnchorLine(hCenterAnchorLine); effectiveLeftMargin = rightMargin; effectiveRightMargin = leftMargin; effectiveHorizontalCenterOffset = -hCenterOffset; } else { effectiveLeftAnchor = QQuickAnchors::LeftAnchor; effectiveRightAnchor = QQuickAnchors::RightAnchor; - effectiveLeft = left; - effectiveRight = right; - effectiveHorizontalCenter = hCenter; + effectiveLeftItem = leftAnchorItem; + effectiveLeftLine = leftAnchorLine; + effectiveRightItem = rightAnchorItem; + effectiveRightLine = rightAnchorLine; + effectiveHorizontalCenterItem = hCenterAnchorItem; + effectiveHorizontalCenterLine = hCenterAnchorLine; effectiveLeftMargin = leftMargin; effectiveRightMargin = rightMargin; effectiveHorizontalCenterOffset = hCenterOffset; @@ -683,42 +743,53 @@ void QQuickAnchorsPrivate::updateHorizontalAnchors() bool invalid = true; qreal width = 0.0; if (usedAnchors & effectiveRightAnchor) { - invalid = calcStretch(effectiveLeft, effectiveRight, effectiveLeftMargin, -effectiveRightMargin, QQuickAnchorLine::Left, width); + invalid = calcStretch(effectiveLeftItem, effectiveLeftLine, + effectiveRightItem, effectiveRightLine, + effectiveLeftMargin, -effectiveRightMargin, + QQuickAnchors::LeftAnchor, width); } else if (usedAnchors & QQuickAnchors::HCenterAnchor) { - invalid = calcStretch(effectiveLeft, effectiveHorizontalCenter, effectiveLeftMargin, effectiveHorizontalCenterOffset, QQuickAnchorLine::Left, width); + invalid = calcStretch(effectiveLeftItem, effectiveLeftLine, + effectiveHorizontalCenterItem, effectiveHorizontalCenterLine, + effectiveLeftMargin, effectiveHorizontalCenterOffset, + QQuickAnchors::LeftAnchor, width); width *= 2; } if (!invalid) setItemWidth(width); //Handle left - if (effectiveLeft.item == item->parentItem()) { - setItemX(adjustedPosition(effectiveLeft.item, effectiveLeft.anchorLine) + effectiveLeftMargin); - } else if (effectiveLeft.item->parentItem() == item->parentItem()) { - setItemX(position(effectiveLeft.item, effectiveLeft.anchorLine) + effectiveLeftMargin); + if (effectiveLeftItem == readParentItem(item)) { + setItemX(adjustedPosition(effectiveLeftItem, effectiveLeftLine) + effectiveLeftMargin); + } else if (readParentItem(effectiveLeftItem) == readParentItem(item)) { + setItemX(position(effectiveLeftItem, effectiveLeftLine) + effectiveLeftMargin); } } else if (usedAnchors & effectiveRightAnchor) { //Handle stretching (left + right case is handled in updateLeftAnchor) if (usedAnchors & QQuickAnchors::HCenterAnchor) { qreal width = 0.0; - bool invalid = calcStretch(effectiveHorizontalCenter, effectiveRight, effectiveHorizontalCenterOffset, -effectiveRightMargin, - QQuickAnchorLine::Left, width); + bool invalid = calcStretch(effectiveHorizontalCenterItem, + effectiveHorizontalCenterLine, + effectiveRightItem, effectiveRightLine, + effectiveHorizontalCenterOffset, -effectiveRightMargin, + QQuickAnchors::LeftAnchor, width); if (!invalid) setItemWidth(width*2); } //Handle right - if (effectiveRight.item == item->parentItem()) { - setItemX(adjustedPosition(effectiveRight.item, effectiveRight.anchorLine) - item->width() - effectiveRightMargin); - } else if (effectiveRight.item->parentItem() == item->parentItem()) { - setItemX(position(effectiveRight.item, effectiveRight.anchorLine) - item->width() - effectiveRightMargin); + if (effectiveRightItem == readParentItem(item)) { + setItemX(adjustedPosition(effectiveRightItem, effectiveRightLine) + - readWidth(item) - effectiveRightMargin); + } else if (readParentItem(effectiveRightItem) == readParentItem(item)) { + setItemX(position(effectiveRightItem, effectiveRightLine) + - readWidth(item) - effectiveRightMargin); } } else if (usedAnchors & QQuickAnchors::HCenterAnchor) { //Handle hCenter - if (effectiveHorizontalCenter.item == item->parentItem()) { - setItemX(adjustedPosition(effectiveHorizontalCenter.item, effectiveHorizontalCenter.anchorLine) - hcenter(item) + effectiveHorizontalCenterOffset); - } else if (effectiveHorizontalCenter.item->parentItem() == item->parentItem()) { - setItemX(position(effectiveHorizontalCenter.item, effectiveHorizontalCenter.anchorLine) - hcenter(item) + effectiveHorizontalCenterOffset); + if (effectiveHorizontalCenterItem == readParentItem(item)) { + setItemX(adjustedPosition(effectiveHorizontalCenterItem, effectiveHorizontalCenterLine) - hcenter(item) + effectiveHorizontalCenterOffset); + } else if (readParentItem(effectiveHorizontalCenterItem) == readParentItem(item)) { + setItemX(position(effectiveHorizontalCenterItem, effectiveHorizontalCenterLine) - hcenter(item) + effectiveHorizontalCenterOffset); } } --updatingHorizontalAnchor; @@ -731,13 +802,14 @@ void QQuickAnchorsPrivate::updateHorizontalAnchors() QQuickAnchorLine QQuickAnchors::top() const { Q_D(const QQuickAnchors); - return d->top; + return QQuickAnchorLine(d->topAnchorItem, d->topAnchorLine); } void QQuickAnchors::setTop(const QQuickAnchorLine &edge) { Q_D(QQuickAnchors); - if (!d->checkVAnchorValid(edge) || d->top == edge) + if (!d->checkVAnchorValid(edge) || + (d->topAnchorItem == edge.item && d->topAnchorLine == edge.anchorLine)) return; d->usedAnchors |= TopAnchor; @@ -747,10 +819,11 @@ void QQuickAnchors::setTop(const QQuickAnchorLine &edge) return; } - QQuickItem *oldTop = d->top.item; - d->top = edge; + QQuickItem *oldTop = d->topAnchorItem; + d->topAnchorItem = edge.item; + d->topAnchorLine = edge.anchorLine; d->remDepend(oldTop); - d->addDepend(d->top.item); + d->addDepend(d->topAnchorItem); emit topChanged(); d->updateVerticalAnchors(); } @@ -759,8 +832,9 @@ void QQuickAnchors::resetTop() { Q_D(QQuickAnchors); d->usedAnchors &= ~TopAnchor; - d->remDepend(d->top.item); - d->top = QQuickAnchorLine(); + d->remDepend(d->topAnchorItem); + d->topAnchorItem = Q_NULLPTR; + d->topAnchorLine = QQuickAnchors::InvalidAnchor; emit topChanged(); d->updateVerticalAnchors(); } @@ -768,13 +842,14 @@ void QQuickAnchors::resetTop() QQuickAnchorLine QQuickAnchors::bottom() const { Q_D(const QQuickAnchors); - return d->bottom; + return QQuickAnchorLine(d->bottomAnchorItem, d->bottomAnchorLine); } void QQuickAnchors::setBottom(const QQuickAnchorLine &edge) { Q_D(QQuickAnchors); - if (!d->checkVAnchorValid(edge) || d->bottom == edge) + if (!d->checkVAnchorValid(edge) || + (d->bottomAnchorItem == edge.item && d->bottomAnchorLine == edge.anchorLine)) return; d->usedAnchors |= BottomAnchor; @@ -784,10 +859,11 @@ void QQuickAnchors::setBottom(const QQuickAnchorLine &edge) return; } - QQuickItem *oldBottom = d->bottom.item; - d->bottom = edge; + QQuickItem *oldBottom = d->bottomAnchorItem; + d->bottomAnchorItem = edge.item; + d->bottomAnchorLine = edge.anchorLine; d->remDepend(oldBottom); - d->addDepend(d->bottom.item); + d->addDepend(d->bottomAnchorItem); emit bottomChanged(); d->updateVerticalAnchors(); } @@ -796,8 +872,9 @@ void QQuickAnchors::resetBottom() { Q_D(QQuickAnchors); d->usedAnchors &= ~BottomAnchor; - d->remDepend(d->bottom.item); - d->bottom = QQuickAnchorLine(); + d->remDepend(d->bottomAnchorItem); + d->bottomAnchorItem = Q_NULLPTR; + d->bottomAnchorLine = QQuickAnchors::InvalidAnchor; emit bottomChanged(); d->updateVerticalAnchors(); } @@ -805,13 +882,14 @@ void QQuickAnchors::resetBottom() QQuickAnchorLine QQuickAnchors::verticalCenter() const { Q_D(const QQuickAnchors); - return d->vCenter; + return QQuickAnchorLine(d->vCenterAnchorItem, d->vCenterAnchorLine); } void QQuickAnchors::setVerticalCenter(const QQuickAnchorLine &edge) { Q_D(QQuickAnchors); - if (!d->checkVAnchorValid(edge) || d->vCenter == edge) + if (!d->checkVAnchorValid(edge) || + (d->vCenterAnchorItem == edge.item && d->vCenterAnchorLine == edge.anchorLine)) return; d->usedAnchors |= VCenterAnchor; @@ -821,10 +899,11 @@ void QQuickAnchors::setVerticalCenter(const QQuickAnchorLine &edge) return; } - QQuickItem *oldVCenter = d->vCenter.item; - d->vCenter = edge; + QQuickItem *oldVCenter = d->vCenterAnchorItem; + d->vCenterAnchorItem = edge.item; + d->vCenterAnchorLine = edge.anchorLine; d->remDepend(oldVCenter); - d->addDepend(d->vCenter.item); + d->addDepend(d->vCenterAnchorItem); emit verticalCenterChanged(); d->updateVerticalAnchors(); } @@ -833,8 +912,9 @@ void QQuickAnchors::resetVerticalCenter() { Q_D(QQuickAnchors); d->usedAnchors &= ~VCenterAnchor; - d->remDepend(d->vCenter.item); - d->vCenter = QQuickAnchorLine(); + d->remDepend(d->vCenterAnchorItem); + d->vCenterAnchorItem = Q_NULLPTR; + d->vCenterAnchorLine = QQuickAnchors::InvalidAnchor; emit verticalCenterChanged(); d->updateVerticalAnchors(); } @@ -842,13 +922,14 @@ void QQuickAnchors::resetVerticalCenter() QQuickAnchorLine QQuickAnchors::baseline() const { Q_D(const QQuickAnchors); - return d->baseline; + return QQuickAnchorLine(d->baselineAnchorItem, d->baselineAnchorLine); } void QQuickAnchors::setBaseline(const QQuickAnchorLine &edge) { Q_D(QQuickAnchors); - if (!d->checkVAnchorValid(edge) || d->baseline == edge) + if (!d->checkVAnchorValid(edge) || + (d->baselineAnchorItem == edge.item && d->baselineAnchorLine == edge.anchorLine)) return; d->usedAnchors |= BaselineAnchor; @@ -858,10 +939,11 @@ void QQuickAnchors::setBaseline(const QQuickAnchorLine &edge) return; } - QQuickItem *oldBaseline = d->baseline.item; - d->baseline = edge; + QQuickItem *oldBaseline = d->baselineAnchorItem; + d->baselineAnchorItem = edge.item; + d->baselineAnchorLine = edge.anchorLine; d->remDepend(oldBaseline); - d->addDepend(d->baseline.item); + d->addDepend(d->baselineAnchorItem); emit baselineChanged(); d->updateVerticalAnchors(); } @@ -870,8 +952,9 @@ void QQuickAnchors::resetBaseline() { Q_D(QQuickAnchors); d->usedAnchors &= ~BaselineAnchor; - d->remDepend(d->baseline.item); - d->baseline = QQuickAnchorLine(); + d->remDepend(d->baselineAnchorItem); + d->baselineAnchorItem = Q_NULLPTR; + d->baselineAnchorLine = QQuickAnchors::InvalidAnchor; emit baselineChanged(); d->updateVerticalAnchors(); } @@ -879,13 +962,14 @@ void QQuickAnchors::resetBaseline() QQuickAnchorLine QQuickAnchors::left() const { Q_D(const QQuickAnchors); - return d->left; + return QQuickAnchorLine(d->leftAnchorItem, d->leftAnchorLine); } void QQuickAnchors::setLeft(const QQuickAnchorLine &edge) { Q_D(QQuickAnchors); - if (!d->checkHAnchorValid(edge) || d->left == edge) + if (!d->checkHAnchorValid(edge) || + (d->leftAnchorItem == edge.item && d->leftAnchorLine == edge.anchorLine)) return; d->usedAnchors |= LeftAnchor; @@ -895,10 +979,11 @@ void QQuickAnchors::setLeft(const QQuickAnchorLine &edge) return; } - QQuickItem *oldLeft = d->left.item; - d->left = edge; + QQuickItem *oldLeft = d->leftAnchorItem; + d->leftAnchorItem = edge.item; + d->leftAnchorLine = edge.anchorLine; d->remDepend(oldLeft); - d->addDepend(d->left.item); + d->addDepend(d->leftAnchorItem); emit leftChanged(); d->updateHorizontalAnchors(); } @@ -907,8 +992,9 @@ void QQuickAnchors::resetLeft() { Q_D(QQuickAnchors); d->usedAnchors &= ~LeftAnchor; - d->remDepend(d->left.item); - d->left = QQuickAnchorLine(); + d->remDepend(d->leftAnchorItem); + d->leftAnchorItem = Q_NULLPTR; + d->leftAnchorLine = QQuickAnchors::InvalidAnchor; emit leftChanged(); d->updateHorizontalAnchors(); } @@ -916,13 +1002,14 @@ void QQuickAnchors::resetLeft() QQuickAnchorLine QQuickAnchors::right() const { Q_D(const QQuickAnchors); - return d->right; + return QQuickAnchorLine(d->rightAnchorItem, d->rightAnchorLine); } void QQuickAnchors::setRight(const QQuickAnchorLine &edge) { Q_D(QQuickAnchors); - if (!d->checkHAnchorValid(edge) || d->right == edge) + if (!d->checkHAnchorValid(edge) || + (d->rightAnchorItem == edge.item && d->rightAnchorLine == edge.anchorLine)) return; d->usedAnchors |= RightAnchor; @@ -932,10 +1019,11 @@ void QQuickAnchors::setRight(const QQuickAnchorLine &edge) return; } - QQuickItem *oldRight = d->right.item; - d->right = edge; + QQuickItem *oldRight = d->rightAnchorItem; + d->rightAnchorItem = edge.item; + d->rightAnchorLine = edge.anchorLine; d->remDepend(oldRight); - d->addDepend(d->right.item); + d->addDepend(d->rightAnchorItem); emit rightChanged(); d->updateHorizontalAnchors(); } @@ -944,8 +1032,9 @@ void QQuickAnchors::resetRight() { Q_D(QQuickAnchors); d->usedAnchors &= ~RightAnchor; - d->remDepend(d->right.item); - d->right = QQuickAnchorLine(); + d->remDepend(d->rightAnchorItem); + d->rightAnchorItem = Q_NULLPTR; + d->rightAnchorLine = QQuickAnchors::InvalidAnchor; emit rightChanged(); d->updateHorizontalAnchors(); } @@ -953,13 +1042,14 @@ void QQuickAnchors::resetRight() QQuickAnchorLine QQuickAnchors::horizontalCenter() const { Q_D(const QQuickAnchors); - return d->hCenter; + return QQuickAnchorLine(d->hCenterAnchorItem, d->hCenterAnchorLine); } void QQuickAnchors::setHorizontalCenter(const QQuickAnchorLine &edge) { Q_D(QQuickAnchors); - if (!d->checkHAnchorValid(edge) || d->hCenter == edge) + if (!d->checkHAnchorValid(edge) || + (d->hCenterAnchorItem == edge.item && d->hCenterAnchorLine == edge.anchorLine)) return; d->usedAnchors |= HCenterAnchor; @@ -969,10 +1059,11 @@ void QQuickAnchors::setHorizontalCenter(const QQuickAnchorLine &edge) return; } - QQuickItem *oldHCenter = d->hCenter.item; - d->hCenter = edge; + QQuickItem *oldHCenter = d->hCenterAnchorItem; + d->hCenterAnchorItem = edge.item; + d->hCenterAnchorLine = edge.anchorLine; d->remDepend(oldHCenter); - d->addDepend(d->hCenter.item); + d->addDepend(d->hCenterAnchorItem); emit horizontalCenterChanged(); d->updateHorizontalAnchors(); } @@ -981,8 +1072,9 @@ void QQuickAnchors::resetHorizontalCenter() { Q_D(QQuickAnchors); d->usedAnchors &= ~HCenterAnchor; - d->remDepend(d->hCenter.item); - d->hCenter = QQuickAnchorLine(); + d->remDepend(d->hCenterAnchorItem); + d->hCenterAnchorItem = Q_NULLPTR; + d->hCenterAnchorLine = QQuickAnchors::InvalidAnchor; emit horizontalCenterChanged(); d->updateHorizontalAnchors(); } @@ -1230,7 +1322,7 @@ void QQuickAnchors::setBaselineOffset(qreal offset) QQuickAnchors::Anchors QQuickAnchors::usedAnchors() const { Q_D(const QQuickAnchors); - return d->usedAnchors; + return static_cast<QQuickAnchors::Anchors>(d->usedAnchors); } bool QQuickAnchorsPrivate::checkHValid() const @@ -1250,10 +1342,11 @@ bool QQuickAnchorsPrivate::checkHAnchorValid(QQuickAnchorLine anchor) const if (!anchor.item) { qmlInfo(item) << QQuickAnchors::tr("Cannot anchor to a null item."); return false; - } else if (anchor.anchorLine & QQuickAnchorLine::Vertical_Mask) { + } else if (anchor.anchorLine & QQuickAnchors::Vertical_Mask) { qmlInfo(item) << QQuickAnchors::tr("Cannot anchor a horizontal edge to a vertical edge."); return false; - } else if (anchor.item != item->parentItem() && anchor.item->parentItem() != item->parentItem()){ + } else if (anchor.item != readParentItem(item) + && readParentItem(anchor.item) != readParentItem(item)) { qmlInfo(item) << QQuickAnchors::tr("Cannot anchor to an item that isn't a parent or sibling."); return false; } else if (anchor.item == item) { @@ -1287,10 +1380,11 @@ bool QQuickAnchorsPrivate::checkVAnchorValid(QQuickAnchorLine anchor) const if (!anchor.item) { qmlInfo(item) << QQuickAnchors::tr("Cannot anchor to a null item."); return false; - } else if (anchor.anchorLine & QQuickAnchorLine::Horizontal_Mask) { + } else if (anchor.anchorLine & QQuickAnchors::Horizontal_Mask) { qmlInfo(item) << QQuickAnchors::tr("Cannot anchor a vertical edge to a horizontal edge."); return false; - } else if (anchor.item != item->parentItem() && anchor.item->parentItem() != item->parentItem()){ + } else if (anchor.item != readParentItem(item) + && readParentItem(anchor.item) != readParentItem(item)) { qmlInfo(item) << QQuickAnchors::tr("Cannot anchor to an item that isn't a parent or sibling."); return false; } else if (anchor.item == item){ diff --git a/src/quick/items/qquickanchors_p.h b/src/quick/items/qquickanchors_p.h index 0e02d80ae8..f00b8b5ba7 100644 --- a/src/quick/items/qquickanchors_p.h +++ b/src/quick/items/qquickanchors_p.h @@ -89,7 +89,14 @@ public: QQuickAnchors(QQuickItem *item, QObject *parent=0); virtual ~QQuickAnchors(); - enum Anchor { + enum Anchor +#if defined(Q_CC_CLANG) || !defined(Q_CC_GNU) // meaning: clang and msvc, but NOT gcc proper (because, you know, Q_CC_CLANG implies Q_CC_GNU) + // Not specifying the enum base type will have MSVC 'interpret' it as signed instead of an unsigned bit-field. + // However, specifying the enum base type breaks many GCCs, which complain that it can't store all values in a 7 bit bitfield. + : uint +#endif + { + InvalidAnchor = 0x0, LeftAnchor = 0x01, RightAnchor = 0x02, TopAnchor = 0x04, diff --git a/src/quick/items/qquickanchors_p_p.h b/src/quick/items/qquickanchors_p_p.h index 205d9a40da..da659946c0 100644 --- a/src/quick/items/qquickanchors_p_p.h +++ b/src/quick/items/qquickanchors_p_p.h @@ -60,24 +60,15 @@ QT_BEGIN_NAMESPACE class QQuickAnchorLine { public: - enum AnchorLine { - Invalid = 0x0, - Left = 0x01, - Right = 0x02, - Top = 0x04, - Bottom = 0x08, - HCenter = 0x10, - VCenter = 0x20, - Baseline = 0x40, - Horizontal_Mask = Left | Right | HCenter, - Vertical_Mask = Top | Bottom | VCenter | Baseline - }; - - QQuickAnchorLine() : item(0), anchorLine(Invalid) {} - QQuickAnchorLine(QQuickItem *i, AnchorLine l) : item(i), anchorLine(l) {} + QQuickAnchorLine() : item(0), anchorLine(QQuickAnchors::InvalidAnchor) {} + QQuickAnchorLine(QQuickItem *i, QQuickAnchors::Anchor l) : item(i), anchorLine(l) {} + QQuickAnchorLine(QQuickItem *i, uint l) + : item(i) + , anchorLine(static_cast<QQuickAnchors::Anchor>(l)) + { Q_ASSERT(l < ((QQuickAnchors::BaselineAnchor << 1) - 1)); } QQuickItem *item; - AnchorLine anchorLine; + QQuickAnchors::Anchor anchorLine; }; inline bool operator==(const QQuickAnchorLine& a, const QQuickAnchorLine& b) @@ -90,13 +81,44 @@ class QQuickAnchorsPrivate : public QObjectPrivate, public QQuickItemChangeListe Q_DECLARE_PUBLIC(QQuickAnchors) public: QQuickAnchorsPrivate(QQuickItem *i) - : componentComplete(true), updatingMe(false), inDestructor(false), centerAligned(true), - leftMarginExplicit(false), rightMarginExplicit(false), topMarginExplicit(false), - bottomMarginExplicit(false), updatingHorizontalAnchor(0), - updatingVerticalAnchor(0), updatingFill(0), updatingCenterIn(0), item(i), usedAnchors(0), fill(0), - centerIn(0), leftMargin(0), rightMargin(0), topMargin(0), bottomMargin(0), - margins(0), vCenterOffset(0), hCenterOffset(0), baselineOffset(0) - + : leftMargin(0) + , rightMargin(0) + , topMargin(0) + , bottomMargin(0) + , margins(0) + , vCenterOffset(0) + , hCenterOffset(0) + , baselineOffset(0) + , item(i) + , fill(Q_NULLPTR) + , centerIn(Q_NULLPTR) + , leftAnchorItem(Q_NULLPTR) + , rightAnchorItem(Q_NULLPTR) + , topAnchorItem(Q_NULLPTR) + , bottomAnchorItem(Q_NULLPTR) + , vCenterAnchorItem(Q_NULLPTR) + , hCenterAnchorItem(Q_NULLPTR) + , baselineAnchorItem(Q_NULLPTR) + , leftAnchorLine(QQuickAnchors::InvalidAnchor) + , leftMarginExplicit(false) + , rightAnchorLine(QQuickAnchors::InvalidAnchor) + , rightMarginExplicit(false) + , topAnchorLine(QQuickAnchors::InvalidAnchor) + , topMarginExplicit(false) + , bottomAnchorLine(QQuickAnchors::InvalidAnchor) + , bottomMarginExplicit(false) + , vCenterAnchorLine(QQuickAnchors::InvalidAnchor) + , updatingMe(false) + , hCenterAnchorLine(QQuickAnchors::InvalidAnchor) + , inDestructor(false) + , baselineAnchorLine(QQuickAnchors::InvalidAnchor) + , centerAligned(true) + , updatingFill(0) + , updatingCenterIn(0) + , updatingHorizontalAnchor(0) + , updatingVerticalAnchor(0) + , componentComplete(true) + , usedAnchors(QQuickAnchors::InvalidAnchor) { } @@ -107,19 +129,6 @@ public: void remDepend(QQuickItem *); bool isItemComplete() const; - bool componentComplete:1; - bool updatingMe:1; - bool inDestructor:1; - bool centerAligned:1; - bool leftMarginExplicit : 1; - bool rightMarginExplicit : 1; - bool topMarginExplicit : 1; - bool bottomMarginExplicit : 1; - uint updatingHorizontalAnchor:2; - uint updatingVerticalAnchor:2; - uint updatingFill:2; - uint updatingCenterIn:2; - void setItemHeight(qreal); void setItemWidth(qreal); void setItemX(qreal); @@ -139,7 +148,9 @@ public: bool checkVValid() const; bool checkHAnchorValid(QQuickAnchorLine anchor) const; bool checkVAnchorValid(QQuickAnchorLine anchor) const; - bool calcStretch(const QQuickAnchorLine &edge1, const QQuickAnchorLine &edge2, qreal offset1, qreal offset2, QQuickAnchorLine::AnchorLine line, qreal &stretch); + bool calcStretch(QQuickItem *edge1Item, QQuickAnchors::Anchor edge1Line, + QQuickItem *edge2Item, QQuickAnchors::Anchor edge2Line, + qreal offset1, qreal offset2, QQuickAnchors::Anchor line, qreal &stretch); bool isMirrored() const; void updateHorizontalAnchors(); @@ -147,20 +158,6 @@ public: void fillChanged(); void centerInChanged(); - QQuickItem *item; - QQuickAnchors::Anchors usedAnchors; - - QQuickItem *fill; - QQuickItem *centerIn; - - QQuickAnchorLine left; - QQuickAnchorLine right; - QQuickAnchorLine top; - QQuickAnchorLine bottom; - QQuickAnchorLine vCenter; - QQuickAnchorLine hCenter; - QQuickAnchorLine baseline; - qreal leftMargin; qreal rightMargin; qreal topMargin; @@ -170,6 +167,44 @@ public: qreal hCenterOffset; qreal baselineOffset; + QQuickItem *item; + + QQuickItem *fill; + QQuickItem *centerIn; + + QQuickItem *leftAnchorItem; + QQuickItem *rightAnchorItem; + QQuickItem *topAnchorItem; + QQuickItem *bottomAnchorItem; + QQuickItem *vCenterAnchorItem; + QQuickItem *hCenterAnchorItem; + QQuickItem *baselineAnchorItem; + + // The bit fields below are carefully laid out in chunks of 1 byte, so the compiler doesn't + // need to generate 2 loads (and combining shifts/ors) to create a single field. + + QQuickAnchors::Anchor leftAnchorLine : 7; + uint leftMarginExplicit : 1; + QQuickAnchors::Anchor rightAnchorLine : 7; + uint rightMarginExplicit : 1; + QQuickAnchors::Anchor topAnchorLine : 7; + uint topMarginExplicit : 1; + QQuickAnchors::Anchor bottomAnchorLine : 7; + uint bottomMarginExplicit : 1; + + QQuickAnchors::Anchor vCenterAnchorLine : 7; + uint updatingMe : 1; + QQuickAnchors::Anchor hCenterAnchorLine : 7; + uint inDestructor : 1; + QQuickAnchors::Anchor baselineAnchorLine : 7; + uint centerAligned : 1; + uint updatingFill : 2; + uint updatingCenterIn : 2; + uint updatingHorizontalAnchor : 2; + uint updatingVerticalAnchor : 2; + + uint componentComplete : 1; + uint usedAnchors : 7; // QQuickAnchors::Anchors static inline QQuickAnchorsPrivate *get(QQuickAnchors *o) { return static_cast<QQuickAnchorsPrivate *>(QObjectPrivate::get(o)); diff --git a/src/quick/items/qquickanimatedimage.cpp b/src/quick/items/qquickanimatedimage.cpp index 42033b6135..6f14bf15fe 100644 --- a/src/quick/items/qquickanimatedimage.cpp +++ b/src/quick/items/qquickanimatedimage.cpp @@ -306,8 +306,9 @@ void QQuickAnimatedImage::load() d->status = Null; emit statusChanged(d->status); - if (sourceSize() != d->oldSourceSize) { - d->oldSourceSize = sourceSize(); + d->currentSourceSize = QSize(0, 0); + if (d->currentSourceSize != d->oldSourceSize) { + d->oldSourceSize = d->currentSourceSize; emit sourceSizeChanged(); } if (isPlaying() != d->oldPlaying) @@ -383,8 +384,9 @@ void QQuickAnimatedImage::movieRequestFinished() d->status = Error; emit statusChanged(d->status); - if (sourceSize() != d->oldSourceSize) { - d->oldSourceSize = sourceSize(); + d->currentSourceSize = QSize(0, 0); + if (d->currentSourceSize != d->oldSourceSize) { + d->oldSourceSize = d->currentSourceSize; emit sourceSizeChanged(); } if (isPlaying() != d->oldPlaying) @@ -421,8 +423,14 @@ void QQuickAnimatedImage::movieRequestFinished() if (isPlaying() != d->oldPlaying) emit playingChanged(); - if (sourceSize() != d->oldSourceSize) { - d->oldSourceSize = sourceSize(); + + if (d->_movie) + d->currentSourceSize = d->_movie->currentPixmap().size(); + else + d->currentSourceSize = QSize(0, 0); + + if (d->currentSourceSize != d->oldSourceSize) { + d->oldSourceSize = d->currentSourceSize; emit sourceSizeChanged(); } } @@ -475,9 +483,7 @@ void QQuickAnimatedImage::onCacheChanged() QSize QQuickAnimatedImage::sourceSize() { Q_D(QQuickAnimatedImage); - if (!d->_movie) - return QSize(0, 0); - return QSize(d->_movie->currentPixmap().size()); + return d->currentSourceSize; } void QQuickAnimatedImage::componentComplete() diff --git a/src/quick/items/qquickanimatedimage_p_p.h b/src/quick/items/qquickanimatedimage_p_p.h index 9b284f966d..ed735d1c9c 100644 --- a/src/quick/items/qquickanimatedimage_p_p.h +++ b/src/quick/items/qquickanimatedimage_p_p.h @@ -72,6 +72,7 @@ public: #ifndef QT_NO_NETWORK , reply(0), redirectCount(0) #endif + , currentSourceSize(0, 0) { } @@ -87,6 +88,7 @@ public: int redirectCount; #endif QMap<int, QQuickPixmap *> frameMap; + QSize currentSourceSize; }; QT_END_NAMESPACE diff --git a/src/quick/items/qquickdrag.cpp b/src/quick/items/qquickdrag.cpp index 4aa54b71df..cc30199253 100644 --- a/src/quick/items/qquickdrag.cpp +++ b/src/quick/items/qquickdrag.cpp @@ -45,6 +45,7 @@ #include <private/qquickitem_p.h> #include <QtQuick/private/qquickevents_p_p.h> #include <private/qquickitemchangelistener_p.h> +#include <private/qquickpixmapcache_p.h> #include <private/qv8engine_p.h> #include <private/qv4scopedvalue_p.h> #include <QtCore/qmimedata.h> @@ -110,6 +111,8 @@ public: bool eventQueued : 1; bool overrideActions : 1; QPointF hotSpot; + QUrl imageSource; + QQuickPixmap pixmapLoader; QStringList keys; QVariantMap externalMimeData; QQuickDrag::DragType dragType; @@ -307,13 +310,14 @@ void QQuickDragAttached::setActive(bool active) else if (active) { if (d->dragType == QQuickDrag::Internal) { d->start(d->supportedActions); - } - else if (d->dragType == QQuickDrag::Automatic) { - // There are different semantics than start() since startDrag() - // may be called after an internal drag is already started. - active = true; + } else { + d->active = true; emit activeChanged(); - d->startDrag(d->supportedActions); + if (d->dragType == QQuickDrag::Automatic) { + // There are different semantics than start() since startDrag() + // may be called after an internal drag is already started. + d->startDrag(d->supportedActions); + } } } else @@ -408,6 +412,43 @@ void QQuickDragAttached::setHotSpot(const QPointF &hotSpot) } /*! + \qmlattachedproperty QUrl QtQuick::Drag::imageSource + \since 5.8 + + This property holds the URL of the image which will be used to represent + the data during the drag and drop operation. Changing this property after + the drag operation has started will have no effect. + + The example below uses an item's contents as a drag image: + + \snippet qml/externaldrag.qml 0 + + \sa Item::grabToImage() +*/ + +QUrl QQuickDragAttached::imageSource() const +{ + Q_D(const QQuickDragAttached); + return d->imageSource; +} + +void QQuickDragAttached::setImageSource(const QUrl &url) +{ + Q_D(QQuickDragAttached); + if (d->imageSource != url) { + d->imageSource = url; + + if (url.isEmpty()) { + d->pixmapLoader.clear(); + } else { + d->pixmapLoader.load(qmlEngine(this), url); + } + + Q_EMIT imageSourceChanged(); + } +} + +/*! \qmlattachedproperty stringlist QtQuick::Drag::keys This property holds a list of keys that can be used by a DropArea to filter drag events. @@ -726,9 +767,9 @@ Qt::DropAction QQuickDragAttachedPrivate::startDrag(Qt::DropActions supportedAct mimeData->setData(it.key(), it.value().toString().toUtf8()); drag->setMimeData(mimeData); - - // TODO: how to handle drag image? - // drag->setPixmap(iconPixmap); + if (pixmapLoader.isReady()) { + drag->setPixmap(QPixmap::fromImage(pixmapLoader.image())); + } emit q->dragStarted(); diff --git a/src/quick/items/qquickdrag_p.h b/src/quick/items/qquickdrag_p.h index c1695e49f0..17721251d9 100644 --- a/src/quick/items/qquickdrag_p.h +++ b/src/quick/items/qquickdrag_p.h @@ -58,6 +58,7 @@ #include <QtCore/qmimedata.h> #include <QtCore/qstringlist.h> +#include <QtCore/qurl.h> #ifndef QT_NO_DRAGANDDROP @@ -247,6 +248,7 @@ class QQuickDragAttached : public QObject Q_PROPERTY(QObject *source READ source WRITE setSource NOTIFY sourceChanged RESET resetSource) Q_PROPERTY(QObject *target READ target NOTIFY targetChanged) Q_PROPERTY(QPointF hotSpot READ hotSpot WRITE setHotSpot NOTIFY hotSpotChanged) + Q_PROPERTY(QUrl imageSource READ imageSource WRITE setImageSource NOTIFY imageSourceChanged REVISION 8) Q_PROPERTY(QStringList keys READ keys WRITE setKeys NOTIFY keysChanged) Q_PROPERTY(QVariantMap mimeData READ mimeData WRITE setMimeData NOTIFY mimeDataChanged) Q_PROPERTY(Qt::DropActions supportedActions READ supportedActions WRITE setSupportedActions NOTIFY supportedActionsChanged) @@ -268,6 +270,9 @@ public: QPointF hotSpot() const; void setHotSpot(const QPointF &hotSpot); + QUrl imageSource() const; + void setImageSource(const QUrl &url); + QStringList keys() const; void setKeys(const QStringList &keys); @@ -300,6 +305,7 @@ Q_SIGNALS: void sourceChanged(); void targetChanged(); void hotSpotChanged(); + void imageSourceChanged(); void keysChanged(); void mimeDataChanged(); void supportedActionsChanged(); diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index b0245f402b..ae138d7ceb 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -881,6 +881,10 @@ QQuickFlickableVisibleArea *QQuickFlickable::visibleArea() \e contentHeight is not equal to the \e height of the Flickable. Allows flicking horizontally if the \e contentWidth is not equal to the \e width of the Flickable. + \li Flickable.AutoFlickIfNeeded - allows flicking vertically if the + \e contentHeight is greater than the \e height of the Flickable. + Allows flicking horizontally if the \e contentWidth is greater than + to the \e width of the Flickable. \li Flickable.HorizontalFlick - allows flicking horizontally. \li Flickable.VerticalFlick - allows flicking vertically. \li Flickable.HorizontalAndVerticalFlick - allows flicking in both directions. @@ -2167,6 +2171,8 @@ qreal QQuickFlickable::vHeight() const bool QQuickFlickable::xflick() const { Q_D(const QQuickFlickable); + if ((d->flickableDirection & QQuickFlickable::AutoFlickIfNeeded) && (vWidth() > width())) + return true; if (d->flickableDirection == QQuickFlickable::AutoFlickDirection) return std::floor(qAbs(vWidth() - width())); return d->flickableDirection & QQuickFlickable::HorizontalFlick; @@ -2175,6 +2181,8 @@ bool QQuickFlickable::xflick() const bool QQuickFlickable::yflick() const { Q_D(const QQuickFlickable); + if ((d->flickableDirection & QQuickFlickable::AutoFlickIfNeeded) && (vHeight() > height())) + return true; if (d->flickableDirection == QQuickFlickable::AutoFlickDirection) return std::floor(qAbs(vHeight() - height())); return d->flickableDirection & QQuickFlickable::VerticalFlick; diff --git a/src/quick/items/qquickflickable_p.h b/src/quick/items/qquickflickable_p.h index 6cf78dcf63..318b8ce473 100644 --- a/src/quick/items/qquickflickable_p.h +++ b/src/quick/items/qquickflickable_p.h @@ -192,7 +192,8 @@ public: QQuickItem *contentItem(); - enum FlickableDirection { AutoFlickDirection=0x00, HorizontalFlick=0x01, VerticalFlick=0x02, HorizontalAndVerticalFlick=0x03 }; + enum FlickableDirection { AutoFlickDirection=0x0, HorizontalFlick=0x1, VerticalFlick=0x2, HorizontalAndVerticalFlick=0x3, + AutoFlickIfNeeded=0xc }; Q_ENUM(FlickableDirection) FlickableDirection flickableDirection() const; void setFlickableDirection(FlickableDirection); diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp index 34b8f0ac49..c04a526bd0 100644 --- a/src/quick/items/qquickimage.cpp +++ b/src/quick/items/qquickimage.cpp @@ -714,9 +714,9 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) sourceRect.height() / nsHeight); if (targetRect.isEmpty() - || !qIsFinite(targetRect.width()) || !qIsFinite(targetRect.height()) + || !qt_is_finite(targetRect.width()) || !qt_is_finite(targetRect.height()) || nsrect.isEmpty() - || !qIsFinite(nsrect.width()) || !qIsFinite(nsrect.height())) { + || !qt_is_finite(nsrect.width()) || !qt_is_finite(nsrect.height())) { delete node; return 0; } diff --git a/src/quick/items/qquickimagebase.cpp b/src/quick/items/qquickimagebase.cpp index 8117baa2fe..60e31631c0 100644 --- a/src/quick/items/qquickimagebase.cpp +++ b/src/quick/items/qquickimagebase.cpp @@ -225,7 +225,7 @@ void QQuickImageBase::load() // sourceSize is set. If sourceSize is not set then the provider default size // will be used, as usual. bool setDevicePixelRatio = false; - if (!d->sourcesize.isValid()) { + if (d->sourcesize.isValid()) { if (loadUrl.scheme() == QLatin1String("image")) { setDevicePixelRatio = true; } else { diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 1100b12cbc..d6fdf5795e 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -1632,7 +1632,7 @@ void QQuickItemPrivate::setLayoutMirror(bool mirror) */ /*! - \qmlproperty enumeration QtQuick::EnterKey::type + \qmlattachedproperty enumeration QtQuick::EnterKey::type Holds the type of the Enter key. @@ -2647,7 +2647,7 @@ void QQuickItem::setParentItem(QQuickItem *parentItem) QQuickItem *scopeItem = 0; - if (hasFocus()) + if (hasFocus() || op->subFocusItem == this) scopeFocusedItem = this; else if (!isFocusScope() && d->subFocusItem) scopeFocusedItem = d->subFocusItem; @@ -3117,7 +3117,6 @@ QQuickItemPrivate::QQuickItemPrivate() , flags(0) , widthValid(false) , heightValid(false) - , baselineOffsetValid(false) , componentComplete(true) , keepMouse(false) , keepTouch(false) @@ -3192,7 +3191,7 @@ void QQuickItemPrivate::init(QQuickItem *parent) registerAccessorProperties(); - baselineOffsetValid = false; + baselineOffset = 0.0; if (parent) { q->setParentItem(parent); @@ -4168,6 +4167,23 @@ QVariant QQuickItem::inputMethodQuery(Qt::InputMethodQuery query) const if (d->extra.isAllocated() && d->extra->enterKeyAttached) v = d->extra->enterKeyAttached->type(); break; + case Qt::ImInputItemClipRectangle: + if (!(!window() ||!isVisible() || qFuzzyIsNull(opacity()))) { + QRectF rect = QRectF(0,0, width(), height()); + const QQuickItem *par = this; + while (QQuickItem *parpar = par->parentItem()) { + rect = parpar->mapRectFromItem(par, rect); + if (parpar->clip()) + rect = rect.intersected(parpar->clipRect()); + par = parpar; + } + rect = par->mapRectToScene(rect); + // once we have the rect in scene coordinates, clip to window + rect = rect.intersected(QRectF(QPoint(0,0), window()->size())); + // map it back to local coordinates + v = mapRectFromScene(rect); + } + break; default: break; } @@ -4179,43 +4195,43 @@ QVariant QQuickItem::inputMethodQuery(Qt::InputMethodQuery query) const QQuickAnchorLine QQuickItemPrivate::left() const { Q_Q(const QQuickItem); - return QQuickAnchorLine(const_cast<QQuickItem *>(q), QQuickAnchorLine::Left); + return QQuickAnchorLine(const_cast<QQuickItem *>(q), QQuickAnchors::LeftAnchor); } QQuickAnchorLine QQuickItemPrivate::right() const { Q_Q(const QQuickItem); - return QQuickAnchorLine(const_cast<QQuickItem *>(q), QQuickAnchorLine::Right); + return QQuickAnchorLine(const_cast<QQuickItem *>(q), QQuickAnchors::RightAnchor); } QQuickAnchorLine QQuickItemPrivate::horizontalCenter() const { Q_Q(const QQuickItem); - return QQuickAnchorLine(const_cast<QQuickItem *>(q), QQuickAnchorLine::HCenter); + return QQuickAnchorLine(const_cast<QQuickItem *>(q), QQuickAnchors::HCenterAnchor); } QQuickAnchorLine QQuickItemPrivate::top() const { Q_Q(const QQuickItem); - return QQuickAnchorLine(const_cast<QQuickItem *>(q), QQuickAnchorLine::Top); + return QQuickAnchorLine(const_cast<QQuickItem *>(q), QQuickAnchors::TopAnchor); } QQuickAnchorLine QQuickItemPrivate::bottom() const { Q_Q(const QQuickItem); - return QQuickAnchorLine(const_cast<QQuickItem *>(q), QQuickAnchorLine::Bottom); + return QQuickAnchorLine(const_cast<QQuickItem *>(q), QQuickAnchors::BottomAnchor); } QQuickAnchorLine QQuickItemPrivate::verticalCenter() const { Q_Q(const QQuickItem); - return QQuickAnchorLine(const_cast<QQuickItem *>(q), QQuickAnchorLine::VCenter); + return QQuickAnchorLine(const_cast<QQuickItem *>(q), QQuickAnchors::VCenterAnchor); } QQuickAnchorLine QQuickItemPrivate::baseline() const { Q_Q(const QQuickItem); - return QQuickAnchorLine(const_cast<QQuickItem *>(q), QQuickAnchorLine::Baseline); + return QQuickAnchorLine(const_cast<QQuickItem *>(q), QQuickAnchors::BaselineAnchor); } /*! @@ -4243,11 +4259,7 @@ QQuickAnchorLine QQuickItemPrivate::baseline() const qreal QQuickItem::baselineOffset() const { Q_D(const QQuickItem); - if (d->baselineOffsetValid) { - return d->baselineOffset; - } else { - return 0.0; - } + return d->baselineOffset; } void QQuickItem::setBaselineOffset(qreal offset) @@ -4257,7 +4269,6 @@ void QQuickItem::setBaselineOffset(qreal offset) return; d->baselineOffset = offset; - d->baselineOffsetValid = true; for (int ii = 0; ii < d->changeListeners.count(); ++ii) { const QQuickItemPrivate::ChangeListener &change = d->changeListeners.at(ii); @@ -6253,6 +6264,8 @@ QPointF QQuickItem::position() const void QQuickItem::setX(qreal v) { Q_D(QQuickItem); + if (qIsNaN(v)) + return; if (d->x == v) return; @@ -6268,6 +6281,8 @@ void QQuickItem::setX(qreal v) void QQuickItem::setY(qreal v) { Q_D(QQuickItem); + if (qIsNaN(v)) + return; if (d->y == v) return; diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h index 46b08b11fb..846063a58b 100644 --- a/src/quick/items/qquickitem_p.h +++ b/src/quick/items/qquickitem_p.h @@ -401,7 +401,6 @@ public: quint32 flags:5; bool widthValid:1; bool heightValid:1; - bool baselineOffsetValid:1; bool componentComplete:1; bool keepMouse:1; bool keepTouch:1; @@ -410,8 +409,8 @@ public: bool antialiasing:1; bool focus:1; bool activeFocus:1; - // Bit 16 bool notifiedFocus:1; + // Bit 16 bool notifiedActiveFocus:1; bool filtersChildMouseEvents:1; bool explicitVisible:1; @@ -427,8 +426,8 @@ public: bool isAccessible:1; bool culled:1; bool hasCursor:1; - // Bit 32 bool hasCursorInChild:1; + // Bit 32 bool hasHoverInChild:1; bool activeFocusOnTab:1; bool implicitAntialiasing:1; diff --git a/src/quick/items/qquickitemgrabresult.cpp b/src/quick/items/qquickitemgrabresult.cpp index f69b5b3f4b..807a2ae304 100644 --- a/src/quick/items/qquickitemgrabresult.cpp +++ b/src/quick/items/qquickitemgrabresult.cpp @@ -59,6 +59,7 @@ class QQuickItemGrabResultPrivate : public QObjectPrivate public: QQuickItemGrabResultPrivate() : cacheEntry(0) + , qmlEngine(0) , texture(0) { } diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index fb5bc3683f..3ccbf4b140 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -292,6 +292,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType<QQuickGridView, 7>(uri, 2, 7, "GridView"); qmlRegisterType<QQuickTextInput, 7>(uri, 2, 7, "TextInput"); qmlRegisterType<QQuickTextEdit, 7>(uri, 2, 7, "TextEdit"); + qmlRegisterType<QQuickPathView, 7>(uri, 2, 7, "PathView"); qmlRegisterUncreatableType<QQuickMouseEvent, 7>(uri, 2, 7, nullptr, QQuickMouseEvent::tr("MouseEvent is only available within handlers in MouseArea")); diff --git a/src/quick/items/qquickopenglshadereffect.cpp b/src/quick/items/qquickopenglshadereffect.cpp index f6f2503cd0..312721ed04 100644 --- a/src/quick/items/qquickopenglshadereffect.cpp +++ b/src/quick/items/qquickopenglshadereffect.cpp @@ -774,7 +774,6 @@ QSGNode *QQuickOpenGLShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQuic builder.appendSourceFile(QStringLiteral(":/qt-project.org/items/shaders/shadereffect.vert")); s.sourceCode[Key::VertexShader] = builder.source(); } - s.className = metaObject()->className(); material->setProgramSource(s); material->attributes = m_common.attributes; diff --git a/src/quick/items/qquickopenglshadereffectnode.cpp b/src/quick/items/qquickopenglshadereffectnode.cpp index 864c968505..c4dd8d5c63 100644 --- a/src/quick/items/qquickopenglshadereffectnode.cpp +++ b/src/quick/items/qquickopenglshadereffectnode.cpp @@ -334,8 +334,6 @@ const char *QQuickCustomMaterialShader::fragmentShader() const bool QQuickOpenGLShaderEffectMaterialKey::operator == (const QQuickOpenGLShaderEffectMaterialKey &other) const { - if (className != other.className) - return false; for (int shaderType = 0; shaderType < ShaderTypeCount; ++shaderType) { if (sourceCode[shaderType] != other.sourceCode[shaderType]) return false; @@ -350,7 +348,7 @@ bool QQuickOpenGLShaderEffectMaterialKey::operator != (const QQuickOpenGLShaderE uint qHash(const QQuickOpenGLShaderEffectMaterialKey &key) { - uint hash = qHash((const void *)key.className); + uint hash = 1; typedef QQuickOpenGLShaderEffectMaterialKey Key; for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) hash = hash * 31337 + qHash(key.sourceCode[shaderType]); diff --git a/src/quick/items/qquickopenglshadereffectnode_p.h b/src/quick/items/qquickopenglshadereffectnode_p.h index 1adfa4dd29..adf5ef730b 100644 --- a/src/quick/items/qquickopenglshadereffectnode_p.h +++ b/src/quick/items/qquickopenglshadereffectnode_p.h @@ -72,7 +72,6 @@ struct QQuickOpenGLShaderEffectMaterialKey { }; QByteArray sourceCode[ShaderTypeCount]; - const char *className; bool operator == (const QQuickOpenGLShaderEffectMaterialKey &other) const; bool operator != (const QQuickOpenGLShaderEffectMaterialKey &other) const; diff --git a/src/quick/items/qquickpainteditem.cpp b/src/quick/items/qquickpainteditem.cpp index 5813b4b115..d21eb93dbf 100644 --- a/src/quick/items/qquickpainteditem.cpp +++ b/src/quick/items/qquickpainteditem.cpp @@ -674,4 +674,11 @@ QSGTextureProvider *QQuickPaintedItem::textureProvider() const return d->textureProvider; } +void QQuickPaintedItem::itemChange(ItemChange change, const ItemChangeData &value) +{ + if (change == ItemDevicePixelRatioHasChanged) + update(); + QQuickItem::itemChange(change, value); +} + QT_END_NAMESPACE diff --git a/src/quick/items/qquickpainteditem.h b/src/quick/items/qquickpainteditem.h index f9e3c91a42..e8b471ac01 100644 --- a/src/quick/items/qquickpainteditem.h +++ b/src/quick/items/qquickpainteditem.h @@ -121,6 +121,7 @@ protected: QQuickPaintedItem(QQuickPaintedItemPrivate &dd, QQuickItem *parent = Q_NULLPTR); QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE; void releaseResources() Q_DECL_OVERRIDE; + void itemChange(ItemChange, const ItemChangeData &) Q_DECL_OVERRIDE; private Q_SLOTS: void invalidateSceneGraph(); diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp index f0bbb1e732..e3d218ff01 100644 --- a/src/quick/items/qquickpathview.cpp +++ b/src/quick/items/qquickpathview.cpp @@ -105,7 +105,8 @@ QQuickPathViewPrivate::QQuickPathViewPrivate() , dragMargin(0), deceleration(100), maximumFlickVelocity(QML_FLICK_DEFAULTMAXVELOCITY) , moveOffset(this, &QQuickPathViewPrivate::setAdjustedOffset), flickDuration(0) , pathItems(-1), requestedIndex(-1), cacheSize(0), requestedZ(0) - , moveReason(Other), moveDirection(Shortest), attType(0), highlightComponent(0), highlightItem(0) + , moveReason(Other), movementDirection(QQuickPathView::Shortest), moveDirection(QQuickPathView::Shortest) + , attType(0), highlightComponent(0), highlightItem(0) , moveHighlight(this, &QQuickPathViewPrivate::setHighlightPosition) , highlightPosition(0) , highlightRangeStart(0), highlightRangeEnd(0) @@ -790,7 +791,7 @@ QQuickItem *QQuickPathView::currentItem() const void QQuickPathView::incrementCurrentIndex() { Q_D(QQuickPathView); - d->moveDirection = QQuickPathViewPrivate::Positive; + d->moveDirection = QQuickPathView::Positive; setCurrentIndex(currentIndex()+1); } @@ -804,7 +805,7 @@ void QQuickPathView::incrementCurrentIndex() void QQuickPathView::decrementCurrentIndex() { Q_D(QQuickPathView); - d->moveDirection = QQuickPathViewPrivate::Negative; + d->moveDirection = QQuickPathView::Negative; setCurrentIndex(currentIndex()-1); } @@ -1373,6 +1374,48 @@ void QQuickPathView::setSnapMode(SnapMode mode) } /*! + \qmlproperty enumeration QtQuick::PathView::movementDirection + \since 5.7 + + This property determines the direction in which items move when setting the current index. + The possible values are: + + \list + \li PathView.Shortest (default) - the items move in the direction that requires the least + movement, which could be either \c Negative or \c Positive. + \li PathView.Negative - the items move backwards towards their destination. + \li PathView.Positive - the items move forwards towards their destination. + \endlist + + For example, suppose that there are 5 items in the model, and \l currentIndex is \c 0. + If currentIndex is set to \c 2, + + \list + \li a \c Positive movement direction will result in the following order: 0, 1, 2 + \li a \c Negative movement direction will result in the following order: 0, 5, 4, 3, 2 + \li a \c Shortest movement direction will result in same order with \c Positive . + \endlist + + \note this property doesn't affect the movement of \l incrementCurrentIndex() and \l decrementCurrentIndex(). +*/ +QQuickPathView::MovementDirection QQuickPathView::movementDirection() const +{ + Q_D(const QQuickPathView); + return d->movementDirection; +} + +void QQuickPathView::setMovementDirection(QQuickPathView::MovementDirection dir) +{ + Q_D(QQuickPathView); + if (dir == d->movementDirection) + return; + d->movementDirection = dir; + if (!d->tl.isActive()) + d->moveDirection = d->movementDirection; + emit movementDirectionChanged(); +} + +/*! \qmlmethod QtQuick::PathView::positionViewAtIndex(int index, PositionMode mode) Positions the view such that the \a index is at the position specified by @@ -1910,7 +1953,7 @@ void QQuickPathView::refill() if (lcItemViewDelegateLifecycle().isDebugEnabled()) { QQuickText *text = qmlobject_cast<QQuickText*>(item); if (text) - qCDebug(lcItemViewDelegateLifecycle) << "idx" << idx << "@" << pos << ": QQuickText" << text->objectName() << text->text().left(40); + qCDebug(lcItemViewDelegateLifecycle) << "idx" << idx << "@" << pos << ": QQuickText" << text->objectName() << text->text().leftRef(40); else qCDebug(lcItemViewDelegateLifecycle) << "idx" << idx << "@" << pos << ":" << item; } @@ -2231,6 +2274,7 @@ void QQuickPathView::movementEnding() emit movingChanged(); emit movementEnded(); } + d->moveDirection = d->movementDirection; } // find the item closest to the snap position @@ -2340,7 +2384,7 @@ void QQuickPathViewPrivate::snapToIndex(int index, MovementReason reason) if (!duration) { tl.set(moveOffset, targetOffset); - } else if (moveDirection == Positive || (moveDirection == Shortest && targetOffset - offset > modelCount/2.0)) { + } else if (moveDirection == QQuickPathView::Positive || (moveDirection == QQuickPathView::Shortest && targetOffset - offset > modelCount/2.0)) { qreal distance = modelCount - targetOffset + offset; if (targetOffset > moveOffset) { tl.move(moveOffset, 0.0, QEasingCurve(QEasingCurve::InQuad), int(duration * offset / distance)); @@ -2349,7 +2393,7 @@ void QQuickPathViewPrivate::snapToIndex(int index, MovementReason reason) } else { tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::InOutQuad), duration); } - } else if (moveDirection == Negative || targetOffset - offset <= -modelCount/2.0) { + } else if (moveDirection == QQuickPathView::Negative || targetOffset - offset <= -modelCount/2.0) { qreal distance = modelCount - offset + targetOffset; if (targetOffset < moveOffset) { tl.move(moveOffset, modelCount, QEasingCurve(targetOffset == 0 ? QEasingCurve::InOutQuad : QEasingCurve::InQuad), int(duration * (modelCount-offset) / distance)); @@ -2361,7 +2405,6 @@ void QQuickPathViewPrivate::snapToIndex(int index, MovementReason reason) } else { tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::InOutQuad), duration); } - moveDirection = Shortest; } QQuickPathViewAttached *QQuickPathView::qmlAttachedProperties(QObject *obj) diff --git a/src/quick/items/qquickpathview_p.h b/src/quick/items/qquickpathview_p.h index 341af02013..daec965f02 100644 --- a/src/quick/items/qquickpathview_p.h +++ b/src/quick/items/qquickpathview_p.h @@ -92,6 +92,7 @@ class Q_AUTOTEST_EXPORT QQuickPathView : public QQuickItem Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged) Q_PROPERTY(int pathItemCount READ pathItemCount WRITE setPathItemCount RESET resetPathItemCount NOTIFY pathItemCountChanged) Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged) + Q_PROPERTY(MovementDirection movementDirection READ movementDirection WRITE setMovementDirection NOTIFY movementDirectionChanged REVISION 7) Q_PROPERTY(int cacheItemCount READ cacheItemCount WRITE setCacheItemCount NOTIFY cacheItemCountChanged) @@ -164,6 +165,11 @@ public: SnapMode snapMode() const; void setSnapMode(SnapMode mode); + enum MovementDirection { Shortest, Negative, Positive }; + Q_ENUM(MovementDirection) + MovementDirection movementDirection() const; + void setMovementDirection(MovementDirection dir); + enum PositionMode { Beginning, Center, End, Contain=4, SnapPosition }; // 3 == Visible in other views Q_ENUM(PositionMode) Q_INVOKABLE void positionViewAtIndex(int index, int mode); @@ -201,6 +207,7 @@ Q_SIGNALS: void highlightMoveDurationChanged(); void movementStarted(); void movementEnded(); + Q_REVISION(7) void movementDirectionChanged(); void flickStarted(); void flickEnded(); void dragStarted(); diff --git a/src/quick/items/qquickpathview_p_p.h b/src/quick/items/qquickpathview_p_p.h index 8236d9efd2..d9c4baf572 100644 --- a/src/quick/items/qquickpathview_p_p.h +++ b/src/quick/items/qquickpathview_p_p.h @@ -171,8 +171,8 @@ public: QPointer<QQmlInstanceModel> model; QVariant modelVariant; MovementReason moveReason; - enum MovementDirection { Shortest, Negative, Positive }; - MovementDirection moveDirection; + QQuickPathView::MovementDirection movementDirection; // default + QQuickPathView::MovementDirection moveDirection; // next movement QQmlOpenMetaObjectType *attType; QQmlComponent *highlightComponent; QQuickItem *highlightItem; diff --git a/src/quick/items/qquickrectangle.cpp b/src/quick/items/qquickrectangle.cpp index 74ca0f482a..b8c680433e 100644 --- a/src/quick/items/qquickrectangle.cpp +++ b/src/quick/items/qquickrectangle.cpp @@ -44,7 +44,6 @@ #include <private/qsgadaptationlayer_p.h> #include <QtGui/qpixmapcache.h> -#include <QtCore/qstringbuilder.h> #include <QtCore/qmath.h> #include <QtCore/qmetaobject.h> diff --git a/src/quick/items/qquickscalegrid.cpp b/src/quick/items/qquickscalegrid.cpp index f860c08bad..d7a0f1b681 100644 --- a/src/quick/items/qquickscalegrid.cpp +++ b/src/quick/items/qquickscalegrid.cpp @@ -136,39 +136,38 @@ QQuickGridScaledImage::QQuickGridScaledImage(QIODevice *data) if (colonId <= 0) return; - QStringList list; - list.append(line.left(colonId).trimmed()); - list.append(line.mid(colonId+1).trimmed()); - - if (list[0] == QLatin1String("border.left")) - l = list[1].toInt(); - else if (list[0] == QLatin1String("border.right")) - r = list[1].toInt(); - else if (list[0] == QLatin1String("border.top")) - t = list[1].toInt(); - else if (list[0] == QLatin1String("border.bottom")) - b = list[1].toInt(); - else if (list[0] == QLatin1String("source")) - imgFile = list[1]; - else if (list[0] == QLatin1String("horizontalTileRule") || list[0] == QLatin1String("horizontalTileMode")) - _h = stringToRule(list[1]); - else if (list[0] == QLatin1String("verticalTileRule") || list[0] == QLatin1String("verticalTileMode")) - _v = stringToRule(list[1]); + const QStringRef property = line.leftRef(colonId).trimmed(); + QStringRef value = line.midRef(colonId + 1).trimmed(); + + if (property == QLatin1String("border.left")) { + l = value.toInt(); + } else if (property == QLatin1String("border.right")) { + r = value.toInt(); + } else if (property == QLatin1String("border.top")) { + t = value.toInt(); + } else if (property == QLatin1String("border.bottom")) { + b = value.toInt(); + } else if (property == QLatin1String("source")) { + if (value.startsWith(QLatin1Char('"')) && value.endsWith(QLatin1Char('"'))) + value = value.mid(1, value.size() - 2); // remove leading/trailing quotes. + imgFile = value.toString(); + } else if (property == QLatin1String("horizontalTileRule") || property == QLatin1String("horizontalTileMode")) { + _h = stringToRule(value); + } else if (property == QLatin1String("verticalTileRule") || property == QLatin1String("verticalTileMode")) { + _v = stringToRule(value); + } } if (l < 0 || r < 0 || t < 0 || b < 0 || imgFile.isEmpty()) return; _l = l; _r = r; _t = t; _b = b; - _pix = imgFile; - if (_pix.startsWith(QLatin1Char('"')) && _pix.endsWith(QLatin1Char('"'))) - _pix = _pix.mid(1, _pix.size() - 2); // remove leading/trailing quotes. } -QQuickBorderImage::TileMode QQuickGridScaledImage::stringToRule(const QString &s) +QQuickBorderImage::TileMode QQuickGridScaledImage::stringToRule(const QStringRef &s) { - QString string = s; + QStringRef string = s; if (string.startsWith(QLatin1Char('"')) && string.endsWith(QLatin1Char('"'))) string = string.mid(1, string.size() - 2); // remove leading/trailing quotes. diff --git a/src/quick/items/qquickscalegrid_p_p.h b/src/quick/items/qquickscalegrid_p_p.h index a424002dfb..7f6a31a7bd 100644 --- a/src/quick/items/qquickscalegrid_p_p.h +++ b/src/quick/items/qquickscalegrid_p_p.h @@ -116,7 +116,7 @@ public: QString pixmapUrl() const; private: - static QQuickBorderImage::TileMode stringToRule(const QString &); + static QQuickBorderImage::TileMode stringToRule(const QStringRef &); private: int _l; diff --git a/src/quick/items/qquicktext_p.h b/src/quick/items/qquicktext_p.h index 0b35ad5f91..40dbd51f39 100644 --- a/src/quick/items/qquicktext_p.h +++ b/src/quick/items/qquicktext_p.h @@ -254,16 +254,16 @@ Q_SIGNALS: void fontChanged(const QFont &font); void colorChanged(); void linkColorChanged(); - void styleChanged(TextStyle style); + void styleChanged(QQuickText::TextStyle style); void styleColorChanged(); - void horizontalAlignmentChanged(HAlignment alignment); - void verticalAlignmentChanged(VAlignment alignment); + void horizontalAlignmentChanged(QQuickText::HAlignment alignment); + void verticalAlignmentChanged(QQuickText::VAlignment alignment); void wrapModeChanged(); void lineCountChanged(); void truncatedChanged(); void maximumLineCountChanged(); - void textFormatChanged(TextFormat textFormat); - void elideModeChanged(TextElideMode mode); + void textFormatChanged(QQuickText::TextFormat textFormat); + void elideModeChanged(QQuickText::TextElideMode mode); void contentSizeChanged(); void lineHeightChanged(qreal lineHeight); void lineHeightModeChanged(LineHeightMode mode); diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp index 8b6cc221d5..45238e2d0c 100644 --- a/src/quick/items/qquicktextcontrol.cpp +++ b/src/quick/items/qquicktextcontrol.cpp @@ -109,6 +109,7 @@ QQuickTextControlPrivate::QQuickTextControlPrivate() overwriteMode(false), acceptRichText(true), cursorVisible(false), + cursorBlinkingEnabled(false), hasFocus(false), hadSelectionOnMousePress(false), wordSelectionEnabled(false), @@ -463,14 +464,30 @@ void QQuickTextControlPrivate::_q_updateCursorPosChanged(const QTextCursor &some void QQuickTextControlPrivate::setBlinkingCursorEnabled(bool enable) { - Q_Q(QQuickTextControl); + if (cursorBlinkingEnabled == enable) + return; + + cursorBlinkingEnabled = enable; + updateCursorFlashTime(); - if (enable && QGuiApplication::styleHints()->cursorFlashTime() > 0) - cursorBlinkTimer.start(QGuiApplication::styleHints()->cursorFlashTime() / 2, q); + if (enable) + connect(qApp->styleHints(), &QStyleHints::cursorFlashTimeChanged, this, &QQuickTextControlPrivate::updateCursorFlashTime); else - cursorBlinkTimer.stop(); + disconnect(qApp->styleHints(), &QStyleHints::cursorFlashTimeChanged, this, &QQuickTextControlPrivate::updateCursorFlashTime); +} - cursorOn = enable; +void QQuickTextControlPrivate::updateCursorFlashTime() +{ + // Note: cursorOn represents the current blinking state controlled by a timer, and + // should not be confused with cursorVisible or cursorBlinkingEnabled. However, we + // interpretate a cursorFlashTime of 0 to mean "always on, never blink". + cursorOn = true; + int flashTime = QGuiApplication::styleHints()->cursorFlashTime(); + + if (cursorBlinkingEnabled && flashTime >= 2) + cursorBlinkTimer.start(flashTime / 2, q_func()); + else + cursorBlinkTimer.stop(); repaintCursor(); } diff --git a/src/quick/items/qquicktextcontrol_p_p.h b/src/quick/items/qquicktextcontrol_p_p.h index f312fcb1ce..0f78feb5de 100644 --- a/src/quick/items/qquicktextcontrol_p_p.h +++ b/src/quick/items/qquicktextcontrol_p_p.h @@ -97,6 +97,7 @@ public: void _q_updateCursorPosChanged(const QTextCursor &someCursor); void setBlinkingCursorEnabled(bool enable); + void updateCursorFlashTime(); void extendWordwiseSelection(int suggestedNewPosition, qreal mouseXPosition); void extendBlockwiseSelection(int suggestedNewPosition); @@ -156,6 +157,7 @@ public: bool overwriteMode : 1; bool acceptRichText : 1; bool cursorVisible : 1; // used to hide the cursor in the preedit area + bool cursorBlinkingEnabled : 1; bool hasFocus : 1; bool hadSelectionOnMousePress : 1; bool wordSelectionEnabled : 1; diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index 8bb788d008..36eb5d3cde 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -1901,6 +1901,9 @@ QVariant QQuickTextEdit::inputMethodQuery(Qt::InputMethodQuery property, QVarian case Qt::ImHints: v = (int)d->effectiveInputMethodHints(); break; + case Qt::ImInputItemClipRectangle: + v = QQuickItem::inputMethodQuery(property); + break; default: if (property == Qt::ImCursorPosition && !argument.isNull()) argument = QVariant(argument.toPointF() - QPointF(d->xoff, d->yoff)); diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index f361d46424..9b7eb4ea4b 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -792,12 +792,8 @@ void QQuickTextInput::setCursorVisible(bool on) d->cursorVisible = on; if (on && isComponentComplete()) QQuickTextUtil::createCursor(d); - if (!d->cursorItem) { - d->setCursorBlinkPeriod(on ? QGuiApplication::styleHints()->cursorFlashTime() : 0); - d->updateType = QQuickTextInputPrivate::UpdatePaintNode; - polish(); - update(); - } + if (!d->cursorItem) + d->updateCursorBlinking(); emit cursorVisibleChanged(d->cursorVisible); } @@ -1858,7 +1854,7 @@ QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData node = new QQuickTextNode(this); d->textNode = node; - const bool showCursor = !isReadOnly() && d->cursorItem == 0 && d->cursorVisible && (d->m_blinkStatus || d->m_blinkPeriod == 0); + const bool showCursor = !isReadOnly() && d->cursorItem == 0 && d->cursorVisible && d->m_blinkStatus; if (!d->textLayoutDirty && oldNode != 0) { if (showCursor) @@ -1954,7 +1950,7 @@ QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property, QVaria return QVariant(d->m_text.mid(d->m_cursor)); case Qt::ImTextBeforeCursor: if (argument.isValid()) - return QVariant(d->m_text.left(d->m_cursor).right(argument.toInt())); + return QVariant(d->m_text.leftRef(d->m_cursor).right(argument.toInt()).toString()); return QVariant(d->m_text.left(d->m_cursor)); default: return QQuickItem::inputMethodQuery(property); @@ -2594,8 +2590,10 @@ void QQuickTextInputPrivate::handleFocusEvent(QFocusEvent *event) { Q_Q(QQuickTextInput); bool focus = event->gotFocus(); - if (!m_readOnly) + if (!m_readOnly) { q->setCursorVisible(focus); + setBlinkingCursorEnabled(focus); + } if (focus) { q->q_updateAlignment(); #ifndef QT_NO_IM @@ -4295,26 +4293,39 @@ bool QQuickTextInputPrivate::emitCursorPositionChanged() } -void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec) +void QQuickTextInputPrivate::setBlinkingCursorEnabled(bool enable) { - Q_Q(QQuickTextInput); - if (msec == m_blinkPeriod) + if (enable == m_blinkEnabled) return; + + m_blinkEnabled = enable; + updateCursorBlinking(); + + if (enable) + connect(qApp->styleHints(), &QStyleHints::cursorFlashTimeChanged, this, &QQuickTextInputPrivate::updateCursorBlinking); + else + disconnect(qApp->styleHints(), &QStyleHints::cursorFlashTimeChanged, this, &QQuickTextInputPrivate::updateCursorBlinking); +} + +void QQuickTextInputPrivate::updateCursorBlinking() +{ + Q_Q(QQuickTextInput); + if (m_blinkTimer) { q->killTimer(m_blinkTimer); - } - if (msec) { - m_blinkTimer = q->startTimer(msec / 2); - m_blinkStatus = 1; - } else { m_blinkTimer = 0; - if (m_blinkStatus == 1) { - updateType = UpdatePaintNode; - q->polish(); - q->update(); - } } - m_blinkPeriod = msec; + + if (m_blinkEnabled && cursorVisible && !cursorItem && !m_readOnly) { + int flashTime = QGuiApplication::styleHints()->cursorFlashTime(); + if (flashTime >= 2) + m_blinkTimer = q->startTimer(flashTime / 2); + } + + m_blinkStatus = 1; + updateType = UpdatePaintNode; + q->polish(); + q->update(); } void QQuickTextInput::timerEvent(QTimerEvent *event) @@ -4351,20 +4362,8 @@ void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event) return; } - if (m_blinkPeriod > 0) { - if (m_blinkTimer) - q->killTimer(m_blinkTimer); - - m_blinkTimer = q->startTimer(m_blinkPeriod / 2); - - if (m_blinkStatus == 0) { - m_blinkStatus = 1; - - updateType = UpdatePaintNode; - q->polish(); - q->update(); - } - } + if (m_blinkEnabled) + updateCursorBlinking(); if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing diff --git a/src/quick/items/qquicktextinput_p.h b/src/quick/items/qquicktextinput_p.h index d2dee2c284..d0461f551e 100644 --- a/src/quick/items/qquicktextinput_p.h +++ b/src/quick/items/qquicktextinput_p.h @@ -323,8 +323,8 @@ Q_SIGNALS: void selectionColorChanged(); void selectedTextColorChanged(); void fontChanged(const QFont &font); - void horizontalAlignmentChanged(HAlignment alignment); - void verticalAlignmentChanged(VAlignment alignment); + void horizontalAlignmentChanged(QQuickTextInput::HAlignment alignment); + void verticalAlignmentChanged(QQuickTextInput::VAlignment alignment); void wrapModeChanged(); void readOnlyChanged(bool isReadOnly); void cursorVisibleChanged(bool isCursorVisible); @@ -333,7 +333,7 @@ Q_SIGNALS: void maximumLengthChanged(int maximumLength); void validatorChanged(); void inputMaskChanged(const QString &inputMask); - void echoModeChanged(EchoMode echoMode); + void echoModeChanged(QQuickTextInput::EchoMode echoMode); void passwordCharacterChanged(); Q_REVISION(3) void passwordMaskDelayChanged(int delay); void displayTextChanged(); @@ -341,7 +341,7 @@ Q_SIGNALS: void activeFocusOnPressChanged(bool activeFocusOnPress); void autoScrollChanged(bool autoScroll); void selectByMouseChanged(bool selectByMouse); - void mouseSelectionModeChanged(SelectionMode mode); + void mouseSelectionModeChanged(QQuickTextInput::SelectionMode mode); void persistentSelectionChanged(); void canPasteChanged(); void canUndoChanged(); diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h index e6bd29bf67..93a8778c40 100644 --- a/src/quick/items/qquicktextinput_p_p.h +++ b/src/quick/items/qquicktextinput_p_p.h @@ -107,7 +107,7 @@ public: #ifndef QT_NO_IM , m_preeditCursor(0) #endif - , m_blinkPeriod(0) + , m_blinkEnabled(false) , m_blinkTimer(0) , m_maxLength(32767) , m_lastCursorPos(-1) @@ -243,7 +243,7 @@ public: #ifndef QT_NO_IM int m_preeditCursor; #endif - int m_blinkPeriod; // 0 for non-blinking cursor + bool m_blinkEnabled; int m_blinkTimer; int m_maxLength; int m_lastCursorPos; @@ -309,8 +309,9 @@ public: return !tripleClickTimer.hasExpired(QGuiApplication::styleHints()->mouseDoubleClickInterval()); } - void setNativeCursorEnabled(bool enabled) { - setCursorBlinkPeriod(enabled && cursorVisible ? QGuiApplication::styleHints()->cursorFlashTime() : 0); } + void setNativeCursorEnabled(bool) { + updateCursorBlinking(); + } int nextMaskBlank(int pos) { @@ -445,7 +446,8 @@ public: #endif void processKeyEvent(QKeyEvent* ev); - void setCursorBlinkPeriod(int msec); + void setBlinkingCursorEnabled(bool enable); + void updateCursorBlinking(); void updateLayout(); void updateBaselineOffset(); diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index f38b3e7693..cdde780932 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -102,6 +102,7 @@ void QQuickWindowPrivate::updateFocusItemTransform() QQuickItemPrivate *focusPrivate = QQuickItemPrivate::get(focus); QGuiApplication::inputMethod()->setInputItemTransform(focusPrivate->itemToWindowTransform()); QGuiApplication::inputMethod()->setInputItemRectangle(QRectF(0, 0, focusPrivate->width, focusPrivate->height)); + focus->updateInputMethod(Qt::ImInputItemClipRectangle); } #endif } @@ -260,6 +261,26 @@ void QQuickWindow::focusInEvent(QFocusEvent *ev) d->updateFocusItemTransform(); } +#ifndef QT_NO_IM +static bool transformDirtyOnItemOrAncestor(const QQuickItem *item) +{ + while (item) { + if (QQuickItemPrivate::get(item)->dirtyAttributes & ( + QQuickItemPrivate::TransformOrigin | + QQuickItemPrivate::Transform | + QQuickItemPrivate::BasicTransform | + QQuickItemPrivate::Position | + QQuickItemPrivate::Size | + QQuickItemPrivate::ParentChanged | + QQuickItemPrivate::Clip)) { + return true; + } + item = item->parentItem(); + } + return false; +} +#endif + void QQuickWindowPrivate::polishItems() { // An item can trigger polish on another item, or itself for that matter, @@ -279,7 +300,17 @@ void QQuickWindowPrivate::polishItems() if (recursionSafeguard == 0) qWarning("QQuickWindow: possible QQuickItem::polish() loop"); - updateFocusItemTransform(); +#ifndef QT_NO_IM + if (QQuickItem *focusItem = q_func()->activeFocusItem()) { + // If the current focus item, or any of its anchestors, has changed location + // inside the window, we need inform IM about it. This to ensure that overlays + // such as selection handles will be updated. + const bool isActiveFocusItem = (focusItem == QGuiApplication::focusObject()); + const bool hasImEnabled = focusItem->inputMethodQuery(Qt::ImEnabled).toBool(); + if (isActiveFocusItem && hasImEnabled && transformDirtyOnItemOrAncestor(focusItem)) + updateFocusItemTransform(); + } +#endif } /*! @@ -4083,6 +4114,12 @@ void QQuickWindow::resetOpenGLState() */ /*! + \qmlproperty Item Window::contentItem + \readonly + \brief The invisible root item of the scene. +*/ + +/*! \qmlproperty Qt::ScreenOrientation Window::contentOrientation This is a hint to the window manager in case it needs to display diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index f277475dbf..5af79747a7 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -496,11 +496,6 @@ void Updater::visitGeometryNode(Node *n) if (e->batch) renderer->invalidateBatchAndOverlappingRenderOrders(e->batch); } - if (n->dirtyState & QSGNode::DirtyMaterial) { - Element *e = n->element(); - if (e->batch && e->batch->isMaterialCompatible(e) == BatchBreaksOnCompare) - renderer->invalidateBatchAndOverlappingRenderOrders(e->batch); - } } SHADOWNODE_TRAVERSE(n) visitNode(child); @@ -598,13 +593,13 @@ void Element::computeBounds() } bounds.map(*node->matrix()); - if (!qIsFinite(bounds.tl.x) || bounds.tl.x == FLT_MAX) + if (!qt_is_finite(bounds.tl.x) || bounds.tl.x == FLT_MAX) bounds.tl.x = -FLT_MAX; - if (!qIsFinite(bounds.tl.y) || bounds.tl.y == FLT_MAX) + if (!qt_is_finite(bounds.tl.y) || bounds.tl.y == FLT_MAX) bounds.tl.y = -FLT_MAX; - if (!qIsFinite(bounds.br.x) || bounds.br.x == -FLT_MAX) + if (!qt_is_finite(bounds.br.x) || bounds.br.x == -FLT_MAX) bounds.br.x = FLT_MAX; - if (!qIsFinite(bounds.br.y) || bounds.br.y == -FLT_MAX) + if (!qt_is_finite(bounds.br.y) || bounds.br.y == -FLT_MAX) bounds.br.y = FLT_MAX; Q_ASSERT(bounds.tl.x <= bounds.br.x); @@ -1241,7 +1236,10 @@ void Renderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state) if (e->isMaterialBlended != blended) { m_rebuild |= Renderer::FullRebuild; e->isMaterialBlended = blended; - } else if (!e->batch) { + } else if (e->batch) { + if (e->batch->isMaterialCompatible(e) == BatchBreaksOnCompare) + invalidateBatchAndOverlappingRenderOrders(e->batch); + } else { m_rebuild |= Renderer::BuildBatches; } } diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h index c56f15d655..01e517e65b 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h @@ -529,7 +529,7 @@ public: float lastOpacity; }; - ShaderManager(QSGDefaultRenderContext *ctx) : blitProgram(0), visualizeProgram(0), context(ctx) { } + ShaderManager(QSGDefaultRenderContext *ctx) : visualizeProgram(0), blitProgram(0), context(ctx) { } ~ShaderManager() { qDeleteAll(rewrittenShaders); qDeleteAll(stockShaders); @@ -542,11 +542,13 @@ public: Shader *prepareMaterial(QSGMaterial *material); Shader *prepareMaterialNoRewrite(QSGMaterial *material); + QOpenGLShaderProgram *visualizeProgram; + +private: QHash<QSGMaterialType *, Shader *> rewrittenShaders; QHash<QSGMaterialType *, Shader *> stockShaders; QOpenGLShaderProgram *blitProgram; - QOpenGLShaderProgram *visualizeProgram; QSGDefaultRenderContext *context; }; diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp index 06c4129a33..098a4a666b 100644 --- a/src/quick/scenegraph/util/qsgatlastexture.cpp +++ b/src/quick/scenegraph/util/qsgatlastexture.cpp @@ -128,6 +128,7 @@ Atlas::Atlas(const QSize &size) : m_allocator(size) , m_texture_id(0) , m_size(size) + , m_atlas_transient_image_threshold(0) , m_allocated(false) { @@ -177,6 +178,11 @@ Atlas::Atlas(const QSize &size) m_use_bgra_fallback = qEnvironmentVariableIsSet("QSG_ATLAS_USE_BGRA_FALLBACK"); m_debug_overlay = qEnvironmentVariableIsSet("QSG_ATLAS_OVERLAY"); + + // images smaller than this will retain their QImage. + // by default no images are retained (favoring memory) + // set to a very large value to retain all images (allowing quick removal from the atlas) + m_atlas_transient_image_threshold = qt_sg_envInt("QSG_ATLAS_TRANSIENT_IMAGE_THRESHOLD", 0); } Atlas::~Atlas() @@ -399,7 +405,10 @@ void Atlas::bind(QSGTexture::Filtering filtering) } else { upload(t); } - t->releaseImage(); + const QSize textureSize = t->textureSize(); + if (textureSize.width() > m_atlas_transient_image_threshold || + textureSize.height() > m_atlas_transient_image_threshold) + t->releaseImage(); qCDebug(QSG_LOG_TIME_TEXTURE).nospace() << "atlastexture uploaded in: " << qsg_renderer_timer.elapsed() << "ms (" << t->textureSize().width() << "x" diff --git a/src/quick/scenegraph/util/qsgatlastexture_p.h b/src/quick/scenegraph/util/qsgatlastexture_p.h index da5acb3fea..cd24645fcf 100644 --- a/src/quick/scenegraph/util/qsgatlastexture_p.h +++ b/src/quick/scenegraph/util/qsgatlastexture_p.h @@ -116,6 +116,8 @@ private: uint m_internalFormat; uint m_externalFormat; + int m_atlas_transient_image_threshold; + uint m_allocated : 1; uint m_use_bgra_fallback: 1; diff --git a/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp b/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp index ec1d316f78..caa296451e 100644 --- a/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp +++ b/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp @@ -382,9 +382,9 @@ QString QSGShaderSourceBuilder::resolveShaderPath(const QString &path) const int idx = path.lastIndexOf(QLatin1Char('.')); QString resolvedPath; if (idx != -1) - resolvedPath = path.left(idx) - + QStringLiteral("_core") - + path.right(path.length() - idx); + resolvedPath = path.leftRef(idx) + + QLatin1String("_core") + + path.rightRef(path.length() - idx); return resolvedPath; } } diff --git a/src/quick/util/qquickanimation.cpp b/src/quick/util/qquickanimation.cpp index adf8f600a0..741a583803 100644 --- a/src/quick/util/qquickanimation.cpp +++ b/src/quick/util/qquickanimation.cpp @@ -986,7 +986,7 @@ void QQuickScriptActionPrivate::debugAction(QDebug d, int indentLevel) const QByteArray ind(indentLevel, ' '); QString exprStr = expr.expression(); int endOfFirstLine = exprStr.indexOf('\n'); - d << "\n" << ind.constData() << exprStr.left(endOfFirstLine); + d << "\n" << ind.constData() << exprStr.leftRef(endOfFirstLine); if (endOfFirstLine != -1 && endOfFirstLine < exprStr.length()) d << "..."; } diff --git a/src/quick/util/qquickglobal.cpp b/src/quick/util/qquickglobal.cpp index 4ad6fdd854..7692cc79f9 100644 --- a/src/quick/util/qquickglobal.cpp +++ b/src/quick/util/qquickglobal.cpp @@ -172,8 +172,8 @@ public: int index = s.indexOf(QLatin1Char(',')); bool xGood, yGood; - float xCoord = s.left(index).toFloat(&xGood); - float yCoord = s.mid(index+1).toFloat(&yGood); + float xCoord = s.leftRef(index).toFloat(&xGood); + float yCoord = s.midRef(index + 1).toFloat(&yGood); if (xGood && yGood) { if (ok) *ok = true; @@ -192,9 +192,9 @@ public: int index2 = s.indexOf(QLatin1Char(','), index+1); bool xGood, yGood, zGood; - float xCoord = s.left(index).toFloat(&xGood); - float yCoord = s.mid(index+1, index2-index-1).toFloat(&yGood); - float zCoord = s.mid(index2+1).toFloat(&zGood); + float xCoord = s.leftRef(index).toFloat(&xGood); + float yCoord = s.midRef(index + 1, index2 - index - 1).toFloat(&yGood); + float zCoord = s.midRef(index2 + 1).toFloat(&zGood); if (xGood && yGood && zGood) { if (ok) *ok = true; @@ -214,10 +214,10 @@ public: int index3 = s.indexOf(QLatin1Char(','), index2+1); bool xGood, yGood, zGood, wGood; - float xCoord = s.left(index).toFloat(&xGood); - float yCoord = s.mid(index+1, index2-index-1).toFloat(&yGood); - float zCoord = s.mid(index2+1, index3-index2-1).toFloat(&zGood); - float wCoord = s.mid(index3+1).toFloat(&wGood); + float xCoord = s.leftRef(index).toFloat(&xGood); + float yCoord = s.midRef(index + 1, index2 - index - 1).toFloat(&yGood); + float zCoord = s.midRef(index2 + 1, index3 - index2 - 1).toFloat(&zGood); + float wCoord = s.midRef(index3 + 1).toFloat(&wGood); if (xGood && yGood && zGood && wGood) { if (ok) *ok = true; @@ -257,10 +257,10 @@ public: if (s.count(QLatin1Char(',')) == 15) { float matValues[16]; bool vOK = true; - QString mutableStr = s; + QStringRef mutableStr(&s); for (int i = 0; vOK && i < 16; ++i) { int cidx = mutableStr.indexOf(QLatin1Char(',')); - matValues[i] = mutableStr.leftRef(cidx).toDouble(&vOK); + matValues[i] = mutableStr.left(cidx).toDouble(&vOK); mutableStr = mutableStr.mid(cidx + 1); } diff --git a/src/quick/util/qquickpath_p.h b/src/quick/util/qquickpath_p.h index d554e2156a..e2c99de44e 100644 --- a/src/quick/util/qquickpath_p.h +++ b/src/quick/util/qquickpath_p.h @@ -335,7 +335,7 @@ class Q_AUTOTEST_EXPORT QQuickPathPercent : public QQuickPathElement Q_OBJECT Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY valueChanged) public: - QQuickPathPercent(QObject *parent=0) : QQuickPathElement(parent) {} + QQuickPathPercent(QObject *parent=0) : QQuickPathElement(parent), _value(0) {} qreal value() const; void setValue(qreal value); diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp index 2b6e8f68c3..597613c9fd 100644 --- a/src/quick/util/qquickpixmapcache.cpp +++ b/src/quick/util/qquickpixmapcache.cpp @@ -455,13 +455,19 @@ QQuickPixmapReader::~QQuickPixmapReader() } jobs.clear(); #ifndef QT_NO_NETWORK - QList<QQuickPixmapReply*> activeJobs = networkJobs.values() + asyncResponses.values(); - foreach (QQuickPixmapReply *reply, activeJobs ) { + + const auto cancelJob = [this](QQuickPixmapReply *reply) { if (reply->loading) { cancelled.append(reply); reply->data = 0; } - } + }; + + for (auto *reply : qAsConst(networkJobs)) + cancelJob(reply); + + for (auto *reply : qAsConst(asyncResponses)) + cancelJob(reply); #endif if (threadObject) threadObject->processJobs(); mutex.unlock(); diff --git a/src/quick/util/qquicksmoothedanimation.cpp b/src/quick/util/qquicksmoothedanimation.cpp index b7eadf5e30..d4956983fb 100644 --- a/src/quick/util/qquicksmoothedanimation.cpp +++ b/src/quick/util/qquicksmoothedanimation.cpp @@ -377,9 +377,8 @@ QQuickSmoothedAnimation::~QQuickSmoothedAnimation() } QQuickSmoothedAnimationPrivate::QQuickSmoothedAnimationPrivate() - : anim(0) + : anim(new QSmoothedAnimation) { - anim = new QSmoothedAnimation; } QQuickSmoothedAnimationPrivate::~QQuickSmoothedAnimationPrivate() diff --git a/src/quick/util/qquickstategroup.cpp b/src/quick/util/qquickstategroup.cpp index 791e38e45d..200f243a1b 100644 --- a/src/quick/util/qquickstategroup.cpp +++ b/src/quick/util/qquickstategroup.cpp @@ -44,9 +44,9 @@ #include <private/qqmlbinding_p.h> #include <private/qqmlglobal_p.h> -#include <QtCore/qstringbuilder.h> #include <QtCore/qstringlist.h> #include <QtCore/qdebug.h> +#include <QtCore/qvector.h> #include <private/qobject_p.h> #include <qqmlinfo.h> @@ -305,7 +305,7 @@ void QQuickStateGroup::componentComplete() for (int ii = 0; ii < d->states.count(); ++ii) { QQuickState *state = d->states.at(ii); if (!state->isNamed()) - state->setName(QLatin1String("anonymousState") % QString::number(++d->unnamedCount)); + state->setName(QLatin1String("anonymousState") + QString::number(++d->unnamedCount)); } if (d->updateAutoState()) { @@ -379,28 +379,29 @@ QQuickTransition *QQuickStateGroupPrivate::findTransition(const QString &from, c (t->fromState() == QLatin1String("*") && t->toState() == QLatin1String("*")))) break; - QStringList fromState; - QStringList toState; + const QString fromStateStr = t->fromState(); + const QString toStateStr = t->toState(); - fromState = t->fromState().split(QLatin1Char(',')); + QVector<QStringRef> fromState = fromStateStr.splitRef(QLatin1Char(',')); for (int jj = 0; jj < fromState.count(); ++jj) fromState[jj] = fromState.at(jj).trimmed(); - toState = t->toState().split(QLatin1Char(',')); + QVector<QStringRef> toState = toStateStr.splitRef(QLatin1Char(',')); for (int jj = 0; jj < toState.count(); ++jj) toState[jj] = toState.at(jj).trimmed(); if (ii == 1) qSwap(fromState, toState); int tScore = 0; - if (fromState.contains(from)) + const QString asterisk = QStringLiteral("*"); + if (fromState.contains(QStringRef(&from))) tScore += 2; - else if (fromState.contains(QLatin1String("*"))) + else if (fromState.contains(QStringRef(&asterisk))) tScore += 1; else continue; - if (toState.contains(to)) + if (toState.contains(QStringRef(&to))) tScore += 2; - else if (toState.contains(QLatin1String("*"))) + else if (toState.contains(QStringRef(&asterisk))) tScore += 1; else continue; diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/controlFromJS.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/controlFromJS.qml index d1db2af367..dd7cb2055d 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/data/controlFromJS.qml +++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/controlFromJS.qml @@ -26,10 +26,10 @@ ** ****************************************************************************/ -import QtQuick 2.0 +import QtQml 2.0 -Rectangle { - Timer { +QtObject { + property var timer: Timer { running: true interval: 1 onTriggered: { @@ -38,7 +38,7 @@ Rectangle { } } - Timer { + property var stopTimer: Timer { id: stopTimer interval: 1000 onTriggered: { @@ -47,7 +47,7 @@ Rectangle { } } - Timer { + property var endTimer: Timer { id: endTimer interval: 1000 onTriggered: Qt.quit(); diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/exit.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/exit.qml index b250524caa..4236d70ea3 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/data/exit.qml +++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/exit.qml @@ -1,6 +1,6 @@ -import QtQuick 2.0 +import QtQml 2.0 -Item { +QtObject { Timer { running: true interval: 1 diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/javascript.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/javascript.qml index 0555d49652..e25c7524f4 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/data/javascript.qml +++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/javascript.qml @@ -1,6 +1,6 @@ -import QtQuick 2.0 +import QtQml 2.0 -Rectangle { +QtObject { function something(i) { if (i > 10) { something(i / 4); @@ -9,8 +9,8 @@ Rectangle { } } - width: 400 - height: 400 + property int width: 400 + property int height: 400 onWidthChanged: something(width); Component.onCompleted: width = 500; diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/signalSourceLocation.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/signalSourceLocation.qml index 25e63669c4..0eff9e9030 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/data/signalSourceLocation.qml +++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/signalSourceLocation.qml @@ -1,8 +1,8 @@ -import QtQuick 2.0 +import QtQml 2.0 -Rectangle { - width: 400 - height: 400 +QtObject { + property int width: 400 + property int height: 400 onWidthChanged: console.log(width); Component.onCompleted: width = 500; diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/test.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/test.qml index 9c36e13c5b..5dd5caf12f 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/data/test.qml +++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/test.qml @@ -1,5 +1,5 @@ -import QtQuick 2.0 +import QtQml 2.0 -Item { +QtObject { } diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/timer.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/timer.qml index 18b8947172..4af555a27b 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/data/timer.qml +++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/timer.qml @@ -1,10 +1,10 @@ -import QtQuick 2.0 +import QtQml 2.0 -Rectangle { - width: 100 - height: 62 +QtObject { + property int width: 100 + property int height: 62 - Timer { + property var timer: Timer { running: true repeat: true interval: 50 diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp index 2187383a31..c1de5ff594 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp +++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp @@ -663,11 +663,11 @@ void tst_QQmlProfilerService::signalSourceLocation() QLatin1String("signalSourceLocation.qml")); expected.line = 8; expected.column = 28; - VERIFY(MessageListQML, 13, expected, CheckAll); + VERIFY(MessageListQML, 9, expected, CheckAll); expected.line = 7; expected.column = 21; - VERIFY(MessageListQML, 15, expected, CheckAll); + VERIFY(MessageListQML, 11, expected, CheckAll); } void tst_QQmlProfilerService::javascript() diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index adf944c7e1..99c18f91a1 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -137,6 +137,7 @@ private slots: void functionDeclarationsInConditionals(); void arrayPop_QTBUG_35979(); + void array_unshift_QTBUG_52065(); void regexpLastMatch(); void indexedAccesses(); @@ -3045,6 +3046,20 @@ void tst_QJSEngine::arrayPop_QTBUG_35979() QCOMPARE(result.toString(), QString("1,3")); } +void tst_QJSEngine::array_unshift_QTBUG_52065() +{ + QJSEngine eng; + QJSValue result = eng.evaluate("[1, 2, 3, 4, 5, 6, 7, 8, 9]"); + QJSValue unshift = result.property(QStringLiteral("unshift")); + unshift.callWithInstance(result, QJSValueList() << QJSValue(0)); + + int len = result.property(QStringLiteral("length")).toInt(); + QCOMPARE(len, 10); + + for (int i = 0; i < len; ++i) + QCOMPARE(result.property(i).toInt(), i); +} + void tst_QJSEngine::regexpLastMatch() { QJSEngine eng; diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro index 5e798f3b48..28f04be5d7 100644 --- a/tests/auto/qml/qml.pro +++ b/tests/auto/qml/qml.pro @@ -69,7 +69,8 @@ qtHaveModule(widgets) { qjsvalue } -SUBDIRS += $$PUBLICTESTS +SUBDIRS += $$PUBLICTESTS \ + qqmlextensionplugin SUBDIRS += $$METATYPETESTS !winrt { # no QProcess on winrt !contains(QT_CONFIG, no-qml-debug): SUBDIRS += debugger diff --git a/tests/auto/qml/qqmlecmascript/data/qtbug_52340.qml b/tests/auto/qml/qqmlecmascript/data/qtbug_52340.qml new file mode 100644 index 0000000000..03f90c15c8 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/qtbug_52340.qml @@ -0,0 +1,13 @@ +import QtQml 2.0 + +QtObject { + property bool someProperty: true + function testCall() { + try { + someProperty(); // should throw + return false + } catch (e) { + return true + } + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/sequenceSort.qml b/tests/auto/qml/qqmlecmascript/data/sequenceSort.qml index b130408c18..74c7cda9a3 100644 --- a/tests/auto/qml/qqmlecmascript/data/sequenceSort.qml +++ b/tests/auto/qml/qqmlecmascript/data/sequenceSort.qml @@ -64,6 +64,16 @@ Item { var actual = msc.reals(realList); return checkResults(expected, actual, fn); } + function doIntVectorTest(intList, fn) { + var expected = createExpected(intList, fn); + var actual = msc.integerVector(intList); + return checkResults(expected, actual, fn); + } + function doRealVectorTest(realList, fn) { + var expected = createExpected(realList, fn); + var actual = msc.realVector(realList); + return checkResults(expected, actual, fn); + } function test_qtbug_25269(useCustomCompare) { return doStringTest( [ "one", "two", "three" ], null ); @@ -92,4 +102,20 @@ Item { var fn = useCustomCompare ? compareNumbers : null; return doRealTest( [ -3.4, 1, 10, 4.23, -30.1, 4.24, 4.21, -1, -1, 12, -100, 87.4, 101.3, -8.88888, 7.76, 10.10, 1.1, -1.1, -0, 11, 12.8, 0.001, -11, -0.75, 99999.99, 11.12, 32.3, 3.333333, 9.876 ], fn ); } + function test_number_vector_insertionSort(useCustomCompare) { + var fn = useCustomCompare ? compareNumbers : null; + return doIntVectorTest( [ 7, 3, 9, 1, 0, -1, 20, -11 ], fn ); + } + function test_number_vector_quickSort(useCustomCompare) { + var fn = useCustomCompare ? compareNumbers : null; + return doIntVectorTest( [ 7, 3, 37, 9, 1, 0, -1, 20, -11, -300, -87, 1, 3, -2, 100, 108, 96, 9, 99999, 12, 11, 11, 12, 11, 13, -13, 10, 10, 10, 8, 12 ], fn ); + } + function test_real_vector_insertionSort(useCustomCompare) { + var fn = useCustomCompare ? compareNumbers : null; + return doRealVectorTest( [ -3.4, 1, 10, 4.23, -30.1, 4.24, 4.21, -1, -1 ], fn ); + } + function test_real_vector_quickSort(useCustomCompare) { + var fn = useCustomCompare ? compareNumbers : null; + return doRealVectorTest( [ -3.4, 1, 10, 4.23, -30.1, 4.24, 4.21, -1, -1, 12, -100, 87.4, 101.3, -8.88888, 7.76, 10.10, 1.1, -1.1, -0, 11, 12.8, 0.001, -11, -0.75, 99999.99, 11.12, 32.3, 3.333333, 9.876 ], fn ); + } } diff --git a/tests/auto/qml/qqmlecmascript/testtypes.cpp b/tests/auto/qml/qqmlecmascript/testtypes.cpp index 2afa21ddd6..d9ddcd71a7 100644 --- a/tests/auto/qml/qqmlecmascript/testtypes.cpp +++ b/tests/auto/qml/qqmlecmascript/testtypes.cpp @@ -295,6 +295,18 @@ public: { return v; } + Q_INVOKABLE QVector<int> integerVector(QVector<int> v) const + { + return v; + } + Q_INVOKABLE QVector<qreal> realVector(QVector<qreal> v) const + { + return v; + } + Q_INVOKABLE QVector<bool> boolVector(QVector<bool> v) const + { + return v; + } }; static MyInheritedQmlObject *theSingletonObject = 0; diff --git a/tests/auto/qml/qqmlecmascript/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h index 81b9b8d7bf..47fb2a56e7 100644 --- a/tests/auto/qml/qqmlecmascript/testtypes.h +++ b/tests/auto/qml/qqmlecmascript/testtypes.h @@ -791,6 +791,8 @@ public: Q_INVOKABLE void method_QScriptValue(QJSValue a) { invoke(14); m_actuals << qVariantFromValue(a); } Q_INVOKABLE void method_intQScriptValue(int a, QJSValue b) { invoke(15); m_actuals << a << qVariantFromValue(b); } Q_INVOKABLE void method_QByteArray(QByteArray value) { invoke(29); m_actuals << value; } + Q_INVOKABLE QJSValue method_intQJSValue(int a, QJSValue b) { invoke(30); m_actuals << a << qVariantFromValue(b); return b.call(); } + Q_INVOKABLE QJSValue method_intQJSValue(int a, int b) { m_actuals << a << b; return QJSValue();} // Should never be called. Q_INVOKABLE void method_overload(int a) { invoke(16); m_actuals << a; } Q_INVOKABLE void method_overload(int a, int b) { invoke(17); m_actuals << a << b; } diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index f71d7efe3a..2f78df1f11 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -322,6 +322,7 @@ private slots: void writeUnregisteredQObjectProperty(); void switchExpression(); void qtbug_46022(); + void qtbug_52340(); private: // static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter); @@ -2944,6 +2945,18 @@ void tst_qqmlecmascript::callQtInvokables() QCOMPARE(o->invoked(), 29); QCOMPARE(o->actuals().count(), 1); QCOMPARE(qvariant_cast<QByteArray>(o->actuals().at(0)), QByteArray("Hello")); + + o->reset(); + QV4::ScopedValue ret(scope, EVALUATE("object.method_intQJSValue(123, function() { return \"Hello world!\";})")); + QCOMPARE(o->error(), false); + QCOMPARE(o->invoked(), 30); + QVERIFY(ret->isString()); + QCOMPARE(ret->toQStringNoThrow(), QString("Hello world!")); + QCOMPARE(o->actuals().count(), 2); + QCOMPARE(o->actuals().at(0), QVariant(123)); + QJSValue callback = qvariant_cast<QJSValue>(o->actuals().at(1)); + QVERIFY(!callback.isNull()); + QVERIFY(callback.isCallable()); } // QTBUG-13047 (check that you can pass registered object types as args) @@ -7331,7 +7344,7 @@ void tst_qqmlecmascript::sequenceSort_data() QTest::newRow("qtbug_25269") << "test_qtbug_25269" << false; - const char *types[] = { "alphabet", "numbers", "reals" }; + const char *types[] = { "alphabet", "numbers", "reals", "number_vector", "real_vector" }; const char *sort[] = { "insertionSort", "quickSort" }; for (size_t t=0 ; t < sizeof(types)/sizeof(types[0]) ; ++t) { @@ -7898,6 +7911,17 @@ void tst_qqmlecmascript::qtbug_46022() QCOMPARE(obj->property("test2").toBool(), true); } +void tst_qqmlecmascript::qtbug_52340() +{ + QQmlComponent component(&engine, testFileUrl("qtbug_52340.qml")); + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + QVariant returnValue; + QVERIFY(QMetaObject::invokeMethod(object.data(), "testCall", Q_RETURN_ARG(QVariant, returnValue))); + QVERIFY(returnValue.isValid()); + QVERIFY(returnValue.toBool()); +} + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" diff --git a/tests/auto/qml/qqmlextensionplugin/qqmlextensionplugin.pro b/tests/auto/qml/qqmlextensionplugin/qqmlextensionplugin.pro new file mode 100644 index 0000000000..af74707c4a --- /dev/null +++ b/tests/auto/qml/qqmlextensionplugin/qqmlextensionplugin.pro @@ -0,0 +1,5 @@ +CONFIG += testcase +TARGET = tst_qqmlextensionplugin +SOURCES += tst_qqmlextensionplugin.cpp +osx:CONFIG -= app_bundle +QT += qml testlib diff --git a/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp b/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp new file mode 100644 index 0000000000..ab5e958323 --- /dev/null +++ b/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore> +#include <QtTest> +#include <QtQml> + +#if defined(Q_OS_WIN) +# define SUFFIX QLatin1String(".dll") +# define DEBUG_SUFFIX QLatin1String("d.dll") + +#elif defined(Q_OS_DARWIN) +# define SUFFIX QLatin1String(".dylib") +# define DEBUG_SUFFIX QLatin1String("_debug.dylib") + +# else // Unix +# define SUFFIX QLatin1String(".so") +#endif + + +class tst_qqmlextensionplugin : public QObject +{ + Q_OBJECT + + bool isDuplicate(QString file, const QList<QString> & files) { +#ifndef DEBUG_SUFFIX + Q_UNUSED(file) + Q_UNUSED(files) + return false; +#else +# ifdef QT_DEBUG + return !file.endsWith(DEBUG_SUFFIX) && files.contains(file.replace(SUFFIX, DEBUG_SUFFIX)); +# else + return file.endsWith(DEBUG_SUFFIX) && files.contains(file.replace(DEBUG_SUFFIX, SUFFIX)); +# endif +#endif + } + +public: + tst_qqmlextensionplugin() {} + +private Q_SLOTS: + void iidCheck_data(); + void iidCheck(); +}; + + +void tst_qqmlextensionplugin::iidCheck_data() +{ + QList<QString> files; + for (QDirIterator it(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath), QDirIterator::Subdirectories); it.hasNext(); ) { + QString file = it.next(); + if (file.endsWith(SUFFIX)) { + files << file; + } + } + + for (QMutableListIterator<QString> it(files); it.hasNext(); ) { + QString file = it.next(); + if (isDuplicate(file, files)) { + it.remove(); + } + } + + QTest::addColumn<QString>("filePath"); + foreach (const QString &file, files) { + QFileInfo fileInfo(file); + QTest::newRow(fileInfo.baseName().toLatin1().data()) << fileInfo.absoluteFilePath(); + } +} + + +void tst_qqmlextensionplugin::iidCheck() +{ + QFETCH(QString, filePath); + + QPluginLoader loader(filePath); + QVERIFY(loader.load()); + QVERIFY(loader.instance() != Q_NULLPTR); + + if (qobject_cast<QQmlExtensionPlugin *>(loader.instance())) { + QString iid = loader.metaData().value(QStringLiteral("IID")).toString(); + QCOMPARE(iid, QLatin1String(QQmlExtensionInterface_iid)); + } +} + + +QTEST_APPLESS_MAIN(tst_qqmlextensionplugin) +#include "tst_qqmlextensionplugin.moc" diff --git a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp index bfa7e2f13f..68739886c4 100644 --- a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp +++ b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp @@ -41,6 +41,8 @@ private slots: void importPathOrder(); void testDesignerSupported(); void uiFormatLoading(); + void completeQmldirPaths_data(); + void completeQmldirPaths(); void cleanup(); }; @@ -146,6 +148,43 @@ void tst_QQmlImport::importPathOrder() QCOMPARE(expectedImportPaths, engine.importPathList()); } +Q_DECLARE_METATYPE(QQmlImports::ImportVersion) + +void tst_QQmlImport::completeQmldirPaths_data() +{ + QTest::addColumn<QString>("uri"); + QTest::addColumn<QStringList>("basePaths"); + QTest::addColumn<int>("majorVersion"); + QTest::addColumn<int>("minorVersion"); + QTest::addColumn<QStringList>("expectedPaths"); + + QTest::newRow("QtQml") << "QtQml" << (QStringList() << "qtbase/qml/" << "path/to/qml") << 2 << 7 + << (QStringList() << "qtbase/qml/QtQml.2.7/qmldir" << "path/to/qml/QtQml.2.7/qmldir" + << "qtbase/qml/QtQml.2/qmldir" << "path/to/qml/QtQml.2/qmldir" + << "qtbase/qml/QtQml/qmldir" << "path/to/qml/QtQml/qmldir"); + + QTest::newRow("QtQml.Models") << "QtQml.Models" << QStringList("qtbase/qml/") << 2 << 2 + << (QStringList() << "qtbase/qml/QtQml/Models.2.2/qmldir" << "qtbase/qml/QtQml.2.2/Models/qmldir" + << "qtbase/qml/QtQml/Models.2/qmldir" << "qtbase/qml/QtQml.2/Models/qmldir" + << "qtbase/qml/QtQml/Models/qmldir"); + + QTest::newRow("org.qt-project.foo.bar") << "org.qt-project.foo.bar" << QStringList("qtbase/qml/") << 0 << 1 + << (QStringList() << "qtbase/qml/org/qt-project/foo/bar.0.1/qmldir" << "qtbase/qml/org/qt-project/foo.0.1/bar/qmldir" << "qtbase/qml/org/qt-project.0.1/foo/bar/qmldir" << "qtbase/qml/org.0.1/qt-project/foo/bar/qmldir" + << "qtbase/qml/org/qt-project/foo/bar.0/qmldir" << "qtbase/qml/org/qt-project/foo.0/bar/qmldir" << "qtbase/qml/org/qt-project.0/foo/bar/qmldir" << "qtbase/qml/org.0/qt-project/foo/bar/qmldir" + << "qtbase/qml/org/qt-project/foo/bar/qmldir"); +} + +void tst_QQmlImport::completeQmldirPaths() +{ + QFETCH(QString, uri); + QFETCH(QStringList, basePaths); + QFETCH(int, majorVersion); + QFETCH(int, minorVersion); + QFETCH(QStringList, expectedPaths); + + QCOMPARE(QQmlImports::completeQmldirPaths(uri, basePaths, majorVersion, minorVersion), expectedPaths); +} + QTEST_MAIN(tst_QQmlImport) #include "tst_qqmlimport.moc" diff --git a/tests/auto/qml/qqmllanguage/BLACKLIST b/tests/auto/qml/qqmllanguage/BLACKLIST deleted file mode 100644 index c1c7e56df9..0000000000 --- a/tests/auto/qml/qqmllanguage/BLACKLIST +++ /dev/null @@ -1,2 +0,0 @@ -[importsPath] -windows diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 1ac1661ea8..98a97ebd66 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -4135,8 +4135,6 @@ void tst_qqmllanguage::dataAlignment() { QVERIFY(sizeof(QQmlVMEMetaData) % sizeof(int) == 0); QVERIFY(sizeof(QQmlVMEMetaData::AliasData) % sizeof(int) == 0); - QVERIFY(sizeof(QQmlVMEMetaData::PropertyData) % sizeof(int) == 0); - QVERIFY(sizeof(QQmlVMEMetaData::MethodData) % sizeof(int) == 0); } void tst_qqmllanguage::deleteSingletons() diff --git a/tests/auto/qml/qqmlmoduleplugin/data/child.qml b/tests/auto/qml/qqmlmoduleplugin/data/child.qml new file mode 100644 index 0000000000..a11ae297d7 --- /dev/null +++ b/tests/auto/qml/qqmlmoduleplugin/data/child.qml @@ -0,0 +1,3 @@ +import org.qtproject.AutoTestQmlPluginType.ChildPlugin 1.0 + +MyChildPluginType { value: 123 } diff --git a/tests/auto/qml/qqmlmoduleplugin/data/child2.qml b/tests/auto/qml/qqmlmoduleplugin/data/child2.qml new file mode 100644 index 0000000000..667164516a --- /dev/null +++ b/tests/auto/qml/qqmlmoduleplugin/data/child2.qml @@ -0,0 +1,3 @@ +import org.qtproject.AutoTestQmlPluginType.ChildPlugin 2.0 + +MyChildPluginType { valueOnlyIn2: 123 } diff --git a/tests/auto/qml/qqmlmoduleplugin/data/child21.qml b/tests/auto/qml/qqmlmoduleplugin/data/child21.qml new file mode 100644 index 0000000000..064d5474e0 --- /dev/null +++ b/tests/auto/qml/qqmlmoduleplugin/data/child21.qml @@ -0,0 +1,3 @@ +import org.qtproject.AutoTestQmlPluginType.ChildPlugin 2.1 + +MyChildPluginType { valueOnlyIn2: 123 } diff --git a/tests/auto/qml/qqmlmoduleplugin/invalidFirstCommandModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/invalidFirstCommandModule/plugin.cpp index 82c3c926fd..fa9782f8c2 100644 --- a/tests/auto/qml/qqmlmoduleplugin/invalidFirstCommandModule/plugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/invalidFirstCommandModule/plugin.cpp @@ -41,7 +41,7 @@ public: class MyPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: MyPlugin() {} diff --git a/tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/plugin.cpp index bb2a344811..fe01507412 100644 --- a/tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/plugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/plugin.cpp @@ -41,7 +41,7 @@ public: class MyPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: MyPlugin() {} diff --git a/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/plugin.cpp index bb2a344811..fe01507412 100644 --- a/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/plugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/plugin.cpp @@ -41,7 +41,7 @@ public: class MyPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: MyPlugin() {} diff --git a/tests/auto/qml/qqmlmoduleplugin/nestedPlugin/nestedPlugin.cpp b/tests/auto/qml/qqmlmoduleplugin/nestedPlugin/nestedPlugin.cpp index 4ca5eb5402..92d30351a7 100644 --- a/tests/auto/qml/qqmlmoduleplugin/nestedPlugin/nestedPlugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/nestedPlugin/nestedPlugin.cpp @@ -56,7 +56,7 @@ public: class MyPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: MyPlugin() {} diff --git a/tests/auto/qml/qqmlmoduleplugin/nonstrictModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/nonstrictModule/plugin.cpp index f48ab16b03..5fc05b91bd 100644 --- a/tests/auto/qml/qqmlmoduleplugin/nonstrictModule/plugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/nonstrictModule/plugin.cpp @@ -41,7 +41,7 @@ public: class MyPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: MyPlugin() {} diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/childplugin/childplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/childplugin/childplugin.cpp new file mode 100644 index 0000000000..515d56a3c4 --- /dev/null +++ b/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/childplugin/childplugin.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QStringList> +#include <QtQml/qqmlextensionplugin.h> +#include <QtQml/qqml.h> +#include <QDebug> + +class MyChildPluginType : public QObject +{ + Q_OBJECT + Q_PROPERTY(int value READ value WRITE setValue) + Q_PROPERTY(int valueOnlyIn2 READ value WRITE setValue) + +public: + MyChildPluginType(QObject *parent=0) : QObject(parent) + { + qWarning("child import2.1 worked"); + } + + int value() const { return v; } + void setValue(int i) { v = i; } + +private: + int v; +}; + + +class MyChildPlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) + +public: + MyChildPlugin() + { + qWarning("child plugin2.1 created"); + } + + void registerTypes(const char *uri) + { + Q_ASSERT(QLatin1String(uri) == "org.qtproject.AutoTestQmlPluginType.ChildPlugin"); + qmlRegisterType<MyChildPluginType>(uri, 2, 1, "MyChildPluginType"); + } +}; + +#include "childplugin.moc" diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/childplugin/childplugin.pro b/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/childplugin/childplugin.pro new file mode 100644 index 0000000000..7a0cd6f80f --- /dev/null +++ b/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/childplugin/childplugin.pro @@ -0,0 +1,12 @@ +TEMPLATE = lib +CONFIG += childplugin +SOURCES = childplugin.cpp +QT = core qml +DESTDIR = ../../imports/org/qtproject/AutoTestQmlPluginType.2.1/ChildPlugin + +QT += core-private gui-private qml-private + +IMPORT_FILES = \ + qmldir + +include (../../../../shared/imports.pri) diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/childplugin/qmldir b/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/childplugin/qmldir new file mode 100644 index 0000000000..c8d6488065 --- /dev/null +++ b/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/childplugin/qmldir @@ -0,0 +1 @@ +plugin childplugin diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/plugin.cpp index 2dc771fad1..6cae5254bc 100644 --- a/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/plugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/plugin.cpp @@ -53,7 +53,7 @@ private: class MyPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: MyPlugin() diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin.2/childplugin/childplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/plugin.2/childplugin/childplugin.cpp new file mode 100644 index 0000000000..56545cfa3c --- /dev/null +++ b/tests/auto/qml/qqmlmoduleplugin/plugin.2/childplugin/childplugin.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QStringList> +#include <QtQml/qqmlextensionplugin.h> +#include <QtQml/qqml.h> +#include <QDebug> + +class MyChildPluginType : public QObject +{ + Q_OBJECT + Q_PROPERTY(int value READ value WRITE setValue) + Q_PROPERTY(int valueOnlyIn2 READ value WRITE setValue) + +public: + MyChildPluginType(QObject *parent=0) : QObject(parent) + { + qWarning("child import2 worked"); + } + + int value() const { return v; } + void setValue(int i) { v = i; } + +private: + int v; +}; + + +class MyChildPlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) + +public: + MyChildPlugin() + { + qWarning("child plugin2 created"); + } + + void registerTypes(const char *uri) + { + Q_ASSERT(QLatin1String(uri) == "org.qtproject.AutoTestQmlPluginType.ChildPlugin"); + qmlRegisterType<MyChildPluginType>(uri, 2, 0, "MyChildPluginType"); + } +}; + +#include "childplugin.moc" diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin.2/childplugin/childplugin.pro b/tests/auto/qml/qqmlmoduleplugin/plugin.2/childplugin/childplugin.pro new file mode 100644 index 0000000000..c9283411f3 --- /dev/null +++ b/tests/auto/qml/qqmlmoduleplugin/plugin.2/childplugin/childplugin.pro @@ -0,0 +1,13 @@ +TEMPLATE = lib +CONFIG += childplugin +SOURCES = childplugin.cpp +QT = core qml +DESTDIR = ../../imports/org/qtproject/AutoTestQmlPluginType.2/ChildPlugin + +QT += core-private gui-private qml-private + +IMPORT_DIR = DESTDIR +IMPORT_FILES = \ + qmldir + +include (../../../../shared/imports.pri) diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin.2/childplugin/qmldir b/tests/auto/qml/qqmlmoduleplugin/plugin.2/childplugin/qmldir new file mode 100644 index 0000000000..c8d6488065 --- /dev/null +++ b/tests/auto/qml/qqmlmoduleplugin/plugin.2/childplugin/qmldir @@ -0,0 +1 @@ +plugin childplugin diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin.2/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/plugin.2/plugin.cpp index 4b25181a86..49a2a747a4 100644 --- a/tests/auto/qml/qqmlmoduleplugin/plugin.2/plugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/plugin.2/plugin.cpp @@ -53,7 +53,7 @@ private: class MyPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: MyPlugin() diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin/childplugin/childplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/plugin/childplugin/childplugin.cpp new file mode 100644 index 0000000000..28490d3d98 --- /dev/null +++ b/tests/auto/qml/qqmlmoduleplugin/plugin/childplugin/childplugin.cpp @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QStringList> +#include <QtQml/qqmlextensionplugin.h> +#include <QtQml/qqml.h> +#include <QDebug> + +class MyChildPluginType : public QObject +{ + Q_OBJECT + Q_PROPERTY(int value READ value WRITE setValue) + +public: + MyChildPluginType(QObject *parent=0) : QObject(parent) + { + qWarning("child import worked"); + } + + int value() const { return v; } + void setValue(int i) { v = i; } + +private: + int v; +}; + + +class MyChildPlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) + +public: + MyChildPlugin() + { + qWarning("child plugin created"); + } + + void registerTypes(const char *uri) + { + Q_ASSERT(QLatin1String(uri) == "org.qtproject.AutoTestQmlPluginType.ChildPlugin"); + qmlRegisterType<MyChildPluginType>(uri, 1, 0, "MyChildPluginType"); + } +}; + +#include "childplugin.moc" diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin/childplugin/childplugin.pro b/tests/auto/qml/qqmlmoduleplugin/plugin/childplugin/childplugin.pro new file mode 100644 index 0000000000..5f5c01f77e --- /dev/null +++ b/tests/auto/qml/qqmlmoduleplugin/plugin/childplugin/childplugin.pro @@ -0,0 +1,12 @@ +TEMPLATE = lib +CONFIG += childplugin +SOURCES = childplugin.cpp +QT = core qml +DESTDIR = ../../imports/org/qtproject/AutoTestQmlPluginType/ChildPlugin + +QT += core-private gui-private qml-private + +IMPORT_FILES = \ + qmldir + +include (../../../../shared/imports.pri) diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin/childplugin/qmldir b/tests/auto/qml/qqmlmoduleplugin/plugin/childplugin/qmldir new file mode 100644 index 0000000000..c8d6488065 --- /dev/null +++ b/tests/auto/qml/qqmlmoduleplugin/plugin/childplugin/qmldir @@ -0,0 +1 @@ +plugin childplugin diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/plugin/plugin.cpp index 7147769406..db51185de6 100644 --- a/tests/auto/qml/qqmlmoduleplugin/plugin/plugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/plugin/plugin.cpp @@ -52,7 +52,7 @@ private: class MyPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: MyPlugin() diff --git a/tests/auto/qml/qqmlmoduleplugin/pluginMixed/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/pluginMixed/plugin.cpp index 8ae091bc0f..e780d4a7fd 100644 --- a/tests/auto/qml/qqmlmoduleplugin/pluginMixed/plugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/pluginMixed/plugin.cpp @@ -43,7 +43,7 @@ public: class MyMixedPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: MyMixedPlugin() diff --git a/tests/auto/qml/qqmlmoduleplugin/pluginVersion/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/pluginVersion/plugin.cpp index 4be0ad4c66..470da6c35f 100644 --- a/tests/auto/qml/qqmlmoduleplugin/pluginVersion/plugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/pluginVersion/plugin.cpp @@ -43,7 +43,7 @@ public: class MyMixedPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: MyMixedPlugin() diff --git a/tests/auto/qml/qqmlmoduleplugin/pluginWithQmlFile/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/pluginWithQmlFile/plugin.cpp index 2c1047450a..60a0a4a3e2 100644 --- a/tests/auto/qml/qqmlmoduleplugin/pluginWithQmlFile/plugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/pluginWithQmlFile/plugin.cpp @@ -33,7 +33,7 @@ class MyPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: void registerTypes(const char *uri) diff --git a/tests/auto/qml/qqmlmoduleplugin/pluginWrongCase/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/pluginWrongCase/plugin.cpp index 4eb875be43..7669d65568 100644 --- a/tests/auto/qml/qqmlmoduleplugin/pluginWrongCase/plugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/pluginWrongCase/plugin.cpp @@ -52,7 +52,7 @@ private: class MyPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: MyPlugin() diff --git a/tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/plugin.cpp index bace4644b3..92211ebf9d 100644 --- a/tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/plugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/plugin.cpp @@ -41,7 +41,7 @@ public: class MyPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: MyPlugin() {} diff --git a/tests/auto/qml/qqmlmoduleplugin/preemptiveModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/preemptiveModule/plugin.cpp index a98398ac94..3df3e9cc81 100644 --- a/tests/auto/qml/qqmlmoduleplugin/preemptiveModule/plugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/preemptiveModule/plugin.cpp @@ -41,7 +41,7 @@ public: class MyPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: MyPlugin() {} diff --git a/tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp index df85d4a327..afdeea80f4 100644 --- a/tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp @@ -40,7 +40,7 @@ public: class MyPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: MyPlugin() {} diff --git a/tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro b/tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro index 5c30d8cc00..889968f6cc 100644 --- a/tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro +++ b/tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro @@ -17,7 +17,10 @@ SUBDIRS =\ preemptedStrictModule\ invalidNamespaceModule\ invalidFirstCommandModule\ - protectedModule + protectedModule\ + plugin/childplugin\ + plugin.2/childplugin\ + plugin.2.1/childplugin tst_qqmlmoduleplugin_pro.depends += plugin SUBDIRS += tst_qqmlmoduleplugin.pro diff --git a/tests/auto/qml/qqmlmoduleplugin/strictModule.2/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/strictModule.2/plugin.cpp index 1e86c0da49..4f5176ae62 100644 --- a/tests/auto/qml/qqmlmoduleplugin/strictModule.2/plugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/strictModule.2/plugin.cpp @@ -41,7 +41,7 @@ public: class MyPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: MyPlugin() {} diff --git a/tests/auto/qml/qqmlmoduleplugin/strictModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/strictModule/plugin.cpp index ad53ac95f3..eaa9aeb1d0 100644 --- a/tests/auto/qml/qqmlmoduleplugin/strictModule/plugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/strictModule/plugin.cpp @@ -41,7 +41,7 @@ public: class MyPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: MyPlugin() {} diff --git a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp index 6ae1a6654f..265492b435 100644 --- a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp @@ -70,6 +70,9 @@ private slots: void importStrictModule(); void importStrictModule_data(); void importProtectedModule(); + void importsChildPlugin(); + void importsChildPlugin2(); + void importsChildPlugin21(); private: QString m_importsDirectory; @@ -575,6 +578,57 @@ void tst_qqmlmoduleplugin::importProtectedModule() QVERIFY(object != 0); } +void tst_qqmlmoduleplugin::importsChildPlugin() +{ + QQmlEngine engine; + engine.addImportPath(m_importsDirectory); + QTest::ignoreMessage(QtWarningMsg, "child plugin created"); + QTest::ignoreMessage(QtWarningMsg, "child import worked"); + QTest::ignoreMessage(QtWarningMsg, "Module 'org.qtproject.AutoTestQmlPluginType.ChildPlugin' does not contain a module identifier directive - it cannot be protected from external registrations."); + QQmlComponent component(&engine, testFileUrl(QStringLiteral("child.qml"))); + foreach (QQmlError err, component.errors()) + qWarning() << err; + VERIFY_ERRORS(0); + QObject *object = component.create(); + QVERIFY(object != 0); + QCOMPARE(object->property("value").toInt(),123); + delete object; +} + +void tst_qqmlmoduleplugin::importsChildPlugin2() +{ + QQmlEngine engine; + engine.addImportPath(m_importsDirectory); + QTest::ignoreMessage(QtWarningMsg, "child plugin2 created"); + QTest::ignoreMessage(QtWarningMsg, "child import2 worked"); + QTest::ignoreMessage(QtWarningMsg, "Module 'org.qtproject.AutoTestQmlPluginType.ChildPlugin' does not contain a module identifier directive - it cannot be protected from external registrations."); + QQmlComponent component(&engine, testFileUrl(QStringLiteral("child2.qml"))); + foreach (QQmlError err, component.errors()) + qWarning() << err; + VERIFY_ERRORS(0); + QObject *object = component.create(); + QVERIFY(object != 0); + QCOMPARE(object->property("value").toInt(),123); + delete object; +} + +void tst_qqmlmoduleplugin::importsChildPlugin21() +{ + QQmlEngine engine; + engine.addImportPath(m_importsDirectory); + QTest::ignoreMessage(QtWarningMsg, "child plugin2.1 created"); + QTest::ignoreMessage(QtWarningMsg, "child import2.1 worked"); + QTest::ignoreMessage(QtWarningMsg, "Module 'org.qtproject.AutoTestQmlPluginType.ChildPlugin' does not contain a module identifier directive - it cannot be protected from external registrations."); + QQmlComponent component(&engine, testFileUrl(QStringLiteral("child21.qml"))); + foreach (QQmlError err, component.errors()) + qWarning() << err; + VERIFY_ERRORS(0); + QObject *object = component.create(); + QVERIFY(object != 0); + QCOMPARE(object->property("value").toInt(),123); + delete object; +} + QTEST_MAIN(tst_qqmlmoduleplugin) #include "tst_qqmlmoduleplugin.moc" diff --git a/tests/auto/qml/qqmlqt/data/qtObjectContents.qml b/tests/auto/qml/qqmlqt/data/qtObjectContents.qml new file mode 100644 index 0000000000..c85e7986e9 --- /dev/null +++ b/tests/auto/qml/qqmlqt/data/qtObjectContents.qml @@ -0,0 +1,10 @@ +import QtQuick 2.0 + +QtObject { + property var values: Object() + Component.onCompleted: { + for (var key in Qt) { + values[key] = Qt[key] + } + } +} diff --git a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp index 413feb0eb4..8150241e4a 100644 --- a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp +++ b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp @@ -90,6 +90,7 @@ private slots: void resolvedUrl(); void later_data(); void later(); + void qtObjectContents(); private: QQmlEngine engine; @@ -1093,6 +1094,51 @@ void tst_qqmlqt::later() delete root; } +void tst_qqmlqt::qtObjectContents() +{ + struct StaticQtMetaObject : public QObject + { + static const QMetaObject *get() + { return &staticQtMetaObject; } + }; + + QQmlComponent component(&engine, testFileUrl("qtObjectContents.qml")); + + QObject *object = component.create(); + QVERIFY(object != 0); + + QVERIFY(object->property("values").canConvert<QJSValue>()); + QVariantMap values = object->property("values").value<QJSValue>().toVariant().toMap(); + + QSet<const char *> keys; + int uniqueKeys = 0; + const QMetaObject *qtMetaObject = StaticQtMetaObject::get(); + for (int ii = 0; ii < qtMetaObject->enumeratorCount(); ++ii) { + QMetaEnum enumerator = qtMetaObject->enumerator(ii); + for (int jj = 0; jj < enumerator.keyCount(); ++jj) { + auto key = enumerator.key(jj); +// qDebug() << "key:" << key; + if (!keys.contains(key)) { + ++uniqueKeys; + keys.insert(key); + } + QVERIFY(values.contains(key)); + QVariant value = values.value(key); + QVERIFY(value.canConvert<int>()); + QCOMPARE(value.toInt(), enumerator.value(jj)); + } + } + QVERIFY(values.contains("Asynchronous")); + QCOMPARE(values.value("Asynchronous").toInt(), 0); + ++uniqueKeys; + QVERIFY(values.contains("Synchronous")); + QCOMPARE(values.value("Synchronous").toInt(), 1); + ++uniqueKeys; + QCOMPARE(values.count(), uniqueKeys); + + delete object; +} + QTEST_MAIN(tst_qqmlqt) #include "tst_qqmlqt.moc" diff --git a/tests/auto/qml/qqmltypeloader/SlowImport/plugin.h b/tests/auto/qml/qqmltypeloader/SlowImport/plugin.h index d3a3b81832..34b3920a38 100644 --- a/tests/auto/qml/qqmltypeloader/SlowImport/plugin.h +++ b/tests/auto/qml/qqmltypeloader/SlowImport/plugin.h @@ -35,7 +35,7 @@ class SlowPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: void registerTypes(const char *uri); diff --git a/tests/auto/qml/qqmltypeloader/data/trim_cache.qml b/tests/auto/qml/qqmltypeloader/data/trim_cache.qml new file mode 100644 index 0000000000..74303977dd --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/trim_cache.qml @@ -0,0 +1,8 @@ +import QtQuick 2.2 +Rectangle +{ + objectName: "dings" + width: 100 + height: 100 + color: "blue" +} diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp index 24358897f7..ef1ea3a897 100644 --- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp +++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp @@ -30,6 +30,9 @@ #include <QtQml/qqmlengine.h> #include <QtQuick/qquickview.h> #include <QtQuick/qquickitem.h> +#include <QtQml/private/qqmlengine_p.h> +#include <QtQml/private/qqmltypeloader_p.h> +#include <QtQml/private/qqmlcompiler_p.h> #include "../../shared/util.h" class tst_QQMLTypeLoader : public QQmlDataTest @@ -39,6 +42,7 @@ class tst_QQMLTypeLoader : public QQmlDataTest private slots: void testLoadComplete(); void loadComponentSynchronously(); + void trimCache(); }; void tst_QQMLTypeLoader::testLoadComplete() @@ -68,6 +72,32 @@ void tst_QQMLTypeLoader::loadComponentSynchronously() QVERIFY(o); } +void tst_QQMLTypeLoader::trimCache() +{ + QQmlEngine engine; + QQmlTypeLoader &loader = QQmlEnginePrivate::get(&engine)->typeLoader; + for (int i = 0; i < 256; ++i) { + QUrl url = testFileUrl("trim_cache.qml"); + url.setQuery(QString::number(i)); + + QQmlTypeData *data = loader.getType(url); + if (i % 5 == 0) // keep references to some of them so that they aren't trimmed + data->compiledData()->addref(); + + data->release(); + } + + for (int i = 0; i < 256; ++i) { + QUrl url = testFileUrl("trim_cache.qml"); + url.setQuery(QString::number(i)); + if (i % 5 == 0) + QVERIFY(loader.isTypeLoaded(url)); + else if (i < 128) + QVERIFY(!loader.isTypeLoaded(url)); + // The cache is free to keep the others. + } +} + QTEST_MAIN(tst_QQMLTypeLoader) #include "tst_qqmltypeloader.moc" diff --git a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp index 300f5b90e5..f506d0f53a 100644 --- a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp +++ b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp @@ -30,6 +30,7 @@ #include <QQmlEngine> #include <QQmlComponent> #include <QDebug> +#include <QJSValueIterator> #include <private/qquickvaluetypes_p.h> #include <private/qqmlglobal_p.h> #include "../../shared/util.h" @@ -89,6 +90,7 @@ private slots: void customValueTypeInQml(); void gadgetInheritance(); void toStringConversion(); + void enumerableProperties(); private: QQmlEngine engine; @@ -1649,6 +1651,25 @@ void tst_qqmlvaluetypes::toStringConversion() QCOMPARE(stringConversion.toString(), StringLessGadget_to_QString(g)); } +void tst_qqmlvaluetypes::enumerableProperties() +{ + QJSEngine engine; + DerivedGadget g; + QJSValue value = engine.toScriptValue(g); + QSet<QString> names; + QJSValueIterator it(value); + while (it.hasNext()) { + it.next(); + const QString name = it.name(); + QVERIFY(!names.contains(name)); + names.insert(name); + } + + QCOMPARE(names.count(), 2); + QVERIFY(names.contains(QStringLiteral("baseProperty"))); + QVERIFY(names.contains(QStringLiteral("derivedProperty"))); +} + QTEST_MAIN(tst_qqmlvaluetypes) diff --git a/tests/auto/quick/qquickanchors/tst_qquickanchors.cpp b/tests/auto/quick/qquickanchors/tst_qquickanchors.cpp index ab111a6cd3..77fa1292c4 100644 --- a/tests/auto/quick/qquickanchors/tst_qquickanchors.cpp +++ b/tests/auto/quick/qquickanchors/tst_qquickanchors.cpp @@ -39,7 +39,6 @@ #include "../shared/visualtestutil.h" Q_DECLARE_METATYPE(QQuickAnchors::Anchor) -Q_DECLARE_METATYPE(QQuickAnchorLine::AnchorLine) using namespace QQuickVisualTestUtil; @@ -351,14 +350,13 @@ void tst_qquickanchors::illegalSets_data() void tst_qquickanchors::reset() { QFETCH(QString, side); - QFETCH(QQuickAnchorLine::AnchorLine, anchorLine); - QFETCH(QQuickAnchors::Anchor, usedAnchor); + QFETCH(QQuickAnchors::Anchor, anchor); QQuickItem *baseItem = new QQuickItem; - QQuickAnchorLine anchor; - anchor.item = baseItem; - anchor.anchorLine = anchorLine; + QQuickAnchorLine anchorLine; + anchorLine.item = baseItem; + anchorLine.anchorLine = anchor; QQuickItem *item = new QQuickItem; QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); @@ -366,11 +364,11 @@ void tst_qquickanchors::reset() const QMetaObject *meta = itemPrivate->anchors()->metaObject(); QMetaProperty p = meta->property(meta->indexOfProperty(side.toUtf8().constData())); - QVERIFY(p.write(itemPrivate->anchors(), qVariantFromValue(anchor))); - QCOMPARE(itemPrivate->anchors()->usedAnchors().testFlag(usedAnchor), true); + QVERIFY(p.write(itemPrivate->anchors(), qVariantFromValue(anchorLine))); + QCOMPARE(itemPrivate->anchors()->usedAnchors().testFlag(anchor), true); QVERIFY(p.reset(itemPrivate->anchors())); - QCOMPARE(itemPrivate->anchors()->usedAnchors().testFlag(usedAnchor), false); + QCOMPARE(itemPrivate->anchors()->usedAnchors().testFlag(anchor), false); delete item; delete baseItem; @@ -379,17 +377,16 @@ void tst_qquickanchors::reset() void tst_qquickanchors::reset_data() { QTest::addColumn<QString>("side"); - QTest::addColumn<QQuickAnchorLine::AnchorLine>("anchorLine"); - QTest::addColumn<QQuickAnchors::Anchor>("usedAnchor"); + QTest::addColumn<QQuickAnchors::Anchor>("anchor"); - QTest::newRow("left") << "left" << QQuickAnchorLine::Left << QQuickAnchors::LeftAnchor; - QTest::newRow("top") << "top" << QQuickAnchorLine::Top << QQuickAnchors::TopAnchor; - QTest::newRow("right") << "right" << QQuickAnchorLine::Right << QQuickAnchors::RightAnchor; - QTest::newRow("bottom") << "bottom" << QQuickAnchorLine::Bottom << QQuickAnchors::BottomAnchor; + QTest::newRow("left") << "left" << QQuickAnchors::LeftAnchor; + QTest::newRow("top") << "top" << QQuickAnchors::TopAnchor; + QTest::newRow("right") << "right" << QQuickAnchors::RightAnchor; + QTest::newRow("bottom") << "bottom" << QQuickAnchors::BottomAnchor; - QTest::newRow("hcenter") << "horizontalCenter" << QQuickAnchorLine::HCenter << QQuickAnchors::HCenterAnchor; - QTest::newRow("vcenter") << "verticalCenter" << QQuickAnchorLine::VCenter << QQuickAnchors::VCenterAnchor; - QTest::newRow("baseline") << "baseline" << QQuickAnchorLine::Baseline << QQuickAnchors::BaselineAnchor; + QTest::newRow("hcenter") << "horizontalCenter" << QQuickAnchors::HCenterAnchor; + QTest::newRow("vcenter") << "verticalCenter" << QQuickAnchors::VCenterAnchor; + QTest::newRow("baseline") << "baseline" << QQuickAnchors::BaselineAnchor; } void tst_qquickanchors::resetConvenience() diff --git a/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp b/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp index b0f0f886a0..b34f58f7c4 100644 --- a/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp +++ b/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp @@ -60,6 +60,7 @@ private slots: void remote_data(); void sourceSize(); void sourceSizeChanges(); + void sourceSizeChanges_intermediate(); void sourceSizeReadOnly(); void invalidSource(); void qtbug_16520(); @@ -205,16 +206,12 @@ void tst_qquickanimatedimage::mirror_notRunning() int frame = anim->currentFrame(); bool playing = anim->isPlaying(); - bool paused = anim->isPlaying(); + bool paused = anim->isPaused(); anim->setProperty("mirror", true); screenshot = window.grabWindow(); screenshot.save("screen.png"); -#if defined(Q_OS_WIN) - // QTBUG-36717 - QSKIP("This test is failing in the CI system under mysterious circumstances"); -#endif QCOMPARE(screenshot, expected); // mirroring should not change the current frame or playing status @@ -374,6 +371,28 @@ void tst_qquickanimatedimage::sourceSizeChanges() delete anim; } +void tst_qquickanimatedimage::sourceSizeChanges_intermediate() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0\nAnimatedImage { readonly property int testWidth: status === AnimatedImage.Ready ? sourceSize.width : -1; source: srcImage }", QUrl::fromLocalFile("")); + QTRY_VERIFY(component.isReady()); + QQmlContext *ctxt = engine.rootContext(); + ctxt->setContextProperty("srcImage", ""); + + QScopedPointer<QQuickAnimatedImage> anim(qobject_cast<QQuickAnimatedImage*>(component.create())); + QVERIFY(anim != 0); + + ctxt->setContextProperty("srcImage", testFileUrl("hearts.gif")); + QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Ready); + QTRY_COMPARE(anim->property("testWidth").toInt(), anim->sourceSize().width()); + + ctxt->setContextProperty("srcImage", testFileUrl("hearts_copy.gif")); + QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Ready); + QTRY_COMPARE(anim->property("testWidth").toInt(), anim->sourceSize().width()); +} + + void tst_qquickanimatedimage::qtbug_16520() { TestHTTPServer server; diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_imagedata.qml b/tests/auto/quick/qquickcanvasitem/data/tst_imagedata.qml new file mode 100644 index 0000000000..7095602ea2 --- /dev/null +++ b/tests/auto/quick/qquickcanvasitem/data/tst_imagedata.qml @@ -0,0 +1,22 @@ +import QtQuick 2.0 +import QtTest 1.1 + +CanvasTestCase { + id:testCase + name: "imagedata" + function init_data() { return testData("2d"); } + function test_rounding(row) { + var canvas = createCanvasObject(row); + var ctx = canvas.getContext('2d'); + var size = 17 + ctx.reset(); + ctx.fillStyle = Qt.rgba(0.7, 0.8, 0.9, 1.0); + ctx.fillRect(0, 0, size, size); + + var center = size / 2; + var imageData = ctx.getImageData(center, center, center, center); + comparePixel(ctx, center, center, imageData.data[0], imageData.data[1], imageData.data[2], imageData.data[3]); + + canvas.destroy(); + } +} diff --git a/tests/auto/quick/qquickcanvasitem/qquickcanvasitem.pro b/tests/auto/quick/qquickcanvasitem/qquickcanvasitem.pro index 3c41d498e5..c6d2a69f8c 100644 --- a/tests/auto/quick/qquickcanvasitem/qquickcanvasitem.pro +++ b/tests/auto/quick/qquickcanvasitem/qquickcanvasitem.pro @@ -25,6 +25,7 @@ OTHER_FILES += \ data/tst_arcto.qml \ data/tst_arc.qml \ data/tst_context.qml \ + data/tst_imagedata.qml \ data/CanvasTestCase.qml \ data/CanvasComponent.qml \ data/tst_image.qml \ diff --git a/tests/auto/quick/qquickdrag/tst_qquickdrag.cpp b/tests/auto/quick/qquickdrag/tst_qquickdrag.cpp index a7b5f4943e..6a919d048e 100644 --- a/tests/auto/quick/qquickdrag/tst_qquickdrag.cpp +++ b/tests/auto/quick/qquickdrag/tst_qquickdrag.cpp @@ -139,6 +139,8 @@ private slots: void cleanupTestCase(); void active(); + void setActive_data(); + void setActive(); void drop(); void move(); void parentChange(); @@ -374,6 +376,50 @@ void tst_QQuickDrag::active() QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0); QCOMPARE(dropTarget.moveEvents, 0); } +void tst_QQuickDrag::setActive_data() +{ + QTest::addColumn<QString>("dragType"); + + QTest::newRow("default") << ""; + QTest::newRow("internal") << "Drag.dragType: Drag.Internal"; + QTest::newRow("none") << "Drag.dragType: Drag.None"; + /* We don't test Drag.Automatic, because that causes QDrag::exec() to be + * invoked, and on some platforms tha's implemented by running a main loop + * until the drag has finished -- and at that point, the Drag.active will + * be false again. */ +} + +// QTBUG-52540 +void tst_QQuickDrag::setActive() +{ + QFETCH(QString, dragType); + + QQuickWindow window; + TestDropTarget dropTarget(window.contentItem()); + dropTarget.setSize(QSizeF(100, 100)); + QQmlComponent component(&engine); + component.setData( + "import QtQuick 2.0\n" + "Item {\n" + "property bool dragActive: Drag.active\n" + "property Item dragTarget: Drag.target\n" + + dragType.toUtf8() + "\n" + "x: 50; y: 50\n" + "width: 10; height: 10\n" + "}", QUrl()); + QScopedPointer<QObject> object(component.create()); + QQuickItem *item = qobject_cast<QQuickItem *>(object.data()); + QVERIFY(item); + item->setParentItem(&dropTarget); + + QCOMPARE(evaluate<bool>(item, "Drag.active"), false); + QCOMPARE(evaluate<bool>(item, "dragActive"), false); + + evaluate<void>(item, "Drag.active = true"); + QCOMPARE(evaluate<bool>(item, "Drag.active"), true); + QCOMPARE(evaluate<bool>(item, "dragActive"), true); +} + void tst_QQuickDrag::drop() { QQuickWindow window; diff --git a/tests/auto/quick/qquickpathview/data/movementDirection.qml b/tests/auto/quick/qquickpathview/data/movementDirection.qml new file mode 100644 index 0000000000..fce914dd68 --- /dev/null +++ b/tests/auto/quick/qquickpathview/data/movementDirection.qml @@ -0,0 +1,43 @@ +import QtQuick 2.0 + +Item { + id: root + width: 320; height: 480 + + PathView { + id: view + objectName: "view" + anchors.fill: parent + + model: ListModel { + ListElement { lColor: "red" } + ListElement { lColor: "green" } + ListElement { lColor: "yellow" } + ListElement { lColor: "blue" } + ListElement { lColor: "purple" } + ListElement { lColor: "gray" } + ListElement { lColor: "brown" } + ListElement { lColor: "thistle" } + } + + delegate: Component { + id: photoDelegate + Rectangle { + id: wrapper + objectName: "wrapper" + width: 40; height: 40; color: lColor + + Text { text: index } + } + } + + snapMode: PathView.SnapToItem + highlightMoveDuration: 1000 + path: Path { + startX: 0+20; startY: root.height/2 + PathLine { x: root.width*2; y: root.height/2 } + } + + Text { text: "Offset: " + view.offset } + } +} diff --git a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp index 51c772f540..6761313210 100644 --- a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp +++ b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp @@ -137,6 +137,8 @@ private slots: void jsArrayChange(); void qtbug42716(); void addCustomAttribute(); + void movementDirection_data(); + void movementDirection(); }; class TestObject : public QObject @@ -2383,6 +2385,72 @@ void tst_QQuickPathView::addCustomAttribute() window->show(); } +void tst_QQuickPathView::movementDirection_data() +{ + QTest::addColumn<QQuickPathView::MovementDirection>("movementdirection"); + QTest::addColumn<int>("toidx"); + QTest::addColumn<qreal>("fromoffset"); + QTest::addColumn<qreal>("tooffset"); + + QTest::newRow("default-shortest") << QQuickPathView::Shortest << 3 << 8.0 << 5.0; + QTest::newRow("negative") << QQuickPathView::Negative << 2 << 0.0 << 6.0; + QTest::newRow("positive") << QQuickPathView::Positive << 3 << 8.0 << 5.0; + +} + +static void verify_offsets(QQuickPathView *pathview, int toidx, qreal fromoffset, qreal tooffset) +{ + pathview->setCurrentIndex(toidx); + bool started = false; + qreal first, second; + QTest::qWait(100); + first = pathview->offset(); + while (1) { + QTest::qWait(10); // highlightMoveDuration: 1000 + second = pathview->offset(); + if (!started && second != first) { // animation started + started = true; + break; + } + } + + if (tooffset > fromoffset) { + QVERIFY(fromoffset <= first); + QVERIFY(first <= second); + QVERIFY(second <= tooffset); + } else { + QVERIFY(fromoffset >= first); + QVERIFY(first >= second); + QVERIFY(second >= tooffset); + } + QTRY_COMPARE(pathview->offset(), tooffset); +} + +void tst_QQuickPathView::movementDirection() +{ + QFETCH(QQuickPathView::MovementDirection, movementdirection); + QFETCH(int, toidx); + QFETCH(qreal, fromoffset); + QFETCH(qreal, tooffset); + + QScopedPointer<QQuickView> window(createView()); + QQuickViewTestUtil::moveMouseAway(window.data()); + window->setSource(testFileUrl("movementDirection.qml")); + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + QCOMPARE(window.data(), qGuiApp->focusWindow()); + + QQuickPathView *pathview = window->rootObject()->findChild<QQuickPathView*>("view"); + QVERIFY(pathview != 0); + QVERIFY(pathview->offset() == 0.0); + QVERIFY(pathview->currentIndex() == 0); + pathview->setMovementDirection(movementdirection); + QVERIFY(pathview->movementDirection() == movementdirection); + + verify_offsets(pathview, toidx, fromoffset, tooffset); +} + QTEST_MAIN(tst_QQuickPathView) #include "tst_qquickpathview.moc" diff --git a/tests/auto/quick/qquickstates/tst_qquickstates.cpp b/tests/auto/quick/qquickstates/tst_qquickstates.cpp index 562d53bceb..9b152b0676 100644 --- a/tests/auto/quick/qquickstates/tst_qquickstates.cpp +++ b/tests/auto/quick/qquickstates/tst_qquickstates.cpp @@ -698,7 +698,7 @@ void tst_qquickstates::anchorChanges() rectPrivate->setState("right"); QCOMPARE(innerRect->x(), qreal(150)); QCOMPARE(aChanges->object(), qobject_cast<QQuickItem*>(innerRect)); - QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->left().anchorLine, QQuickAnchorLine::Invalid); //### was reset (how do we distinguish from not set at all) + QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->left().anchorLine, QQuickAnchors::InvalidAnchor); //### was reset (how do we distinguish from not set at all) QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->right().item, rectPrivate->right().item); QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->right().anchorLine, rectPrivate->right().anchorLine); @@ -891,7 +891,7 @@ void tst_qquickstates::anchorChangesRTL() rectPrivate->setState("right"); QCOMPARE(innerRect->x(), offsetRTL(rect, innerRect) - qreal(150)); QCOMPARE(aChanges->object(), qobject_cast<QQuickItem*>(innerRect)); - QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->left().anchorLine, QQuickAnchorLine::Invalid); //### was reset (how do we distinguish from not set at all) + QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->left().anchorLine, QQuickAnchors::InvalidAnchor); //### was reset (how do we distinguish from not set at all) QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->right().item, rectPrivate->right().item); QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->right().anchorLine, rectPrivate->right().anchorLine); diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp index 7ea36bbafa..8b7d8c0711 100644 --- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp +++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp @@ -701,7 +701,7 @@ void tst_qquicktext::textFormat() QQuickText *text = qobject_cast<QQuickText *>(object.data()); QVERIFY(text); - QSignalSpy spy(text, SIGNAL(textFormatChanged(TextFormat))); + QSignalSpy spy(text, &QQuickText::textFormatChanged); QCOMPARE(text->textFormat(), QQuickText::AutoText); @@ -915,8 +915,10 @@ void tst_qquicktext::hAlignImplicitWidth() // Try to check whether alignment works by checking the number of black // pixels in the thirds of the grabbed image. - const int windowWidth = 220; - const int textWidth = qCeil(text->implicitWidth()); + // QQuickWindow::grabWindow() scales the returned image by the devicePixelRatio of the screen. + const qreal devicePixelRatio = view.screen()->devicePixelRatio(); + const int windowWidth = 220 * devicePixelRatio; + const int textWidth = qCeil(text->implicitWidth()) * devicePixelRatio; QVERIFY2(textWidth < windowWidth, "System font too large."); const int sectionWidth = textWidth / 3; const int centeredSection1 = (windowWidth - textWidth) / 2; diff --git a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp index e26bf6f4e4..24cfadc2d3 100644 --- a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp +++ b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp @@ -1390,7 +1390,7 @@ void tst_qquicktextinput::mouseSelectionMode_accessors() QQuickTextInput *input = qobject_cast<QQuickTextInput *>(object.data()); QVERIFY(input); - QSignalSpy spy(input, SIGNAL(mouseSelectionModeChanged(SelectionMode))); + QSignalSpy spy(input, &QQuickTextInput::mouseSelectionModeChanged); QCOMPARE(input->mouseSelectionMode(), QQuickTextInput::SelectCharacters); diff --git a/tests/auto/quick/quick.pro b/tests/auto/quick/quick.pro index a528810cae..fecd1aea58 100644 --- a/tests/auto/quick/quick.pro +++ b/tests/auto/quick/quick.pro @@ -81,6 +81,7 @@ QUICKTESTS = \ qquickvisualdatamodel \ qquickview \ qquickcanvasitem \ + qquickdesignersupport \ qquickscreen \ touchmouse \ scenegraph diff --git a/tests/benchmarks/qml/creation/tst_creation.cpp b/tests/benchmarks/qml/creation/tst_creation.cpp index 2c8aa04a6a..fa94fd4d46 100644 --- a/tests/benchmarks/qml/creation/tst_creation.cpp +++ b/tests/benchmarks/qml/creation/tst_creation.cpp @@ -74,6 +74,9 @@ private slots: void bindings_parent_qml(); + void anchors_creation(); + void anchors_heightChange(); + private: QQmlEngine engine; }; @@ -462,6 +465,38 @@ void tst_creation::bindings_parent_qml() delete obj; } +void tst_creation::anchors_creation() +{ + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0\nItem { Item { anchors.bottom: parent.bottom } }", QUrl()); + + QObject *obj = component.create(); + delete obj; + + QBENCHMARK { + QObject *obj = component.create(); + delete obj; + } +} + +void tst_creation::anchors_heightChange() +{ + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0\nItem { Item { anchors.bottom: parent.bottom } }", QUrl()); + + QObject *obj = component.create(); + auto item = qobject_cast<QQuickItem *>(obj); + Q_ASSERT(item); + int height = 1; + + QBENCHMARK { + item->setHeight(height); + height += 1; + } + + delete obj; +} + QTEST_MAIN(tst_creation) #include "tst_creation.moc" diff --git a/tests/manual/highdpi/imageprovider.cpp b/tests/manual/highdpi/imageprovider.cpp index 1856a1ea9a..33a69cb87e 100644 --- a/tests/manual/highdpi/imageprovider.cpp +++ b/tests/manual/highdpi/imageprovider.cpp @@ -79,7 +79,7 @@ public: class ImageProviderExtensionPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: void registerTypes(const char *uri) { @@ -95,7 +95,4 @@ public: }; -#define QQmlExtensionInterface_iid "org.qt-project.Qt.QQmlExtensionInterface" - - #include "imageprovider.moc" diff --git a/tests/manual/qmlplugindump/tests/dumper/Dummy/dummy_plugin.h b/tests/manual/qmlplugindump/tests/dumper/Dummy/dummy_plugin.h index 739eae0f8a..86e80e6a08 100644 --- a/tests/manual/qmlplugindump/tests/dumper/Dummy/dummy_plugin.h +++ b/tests/manual/qmlplugindump/tests/dumper/Dummy/dummy_plugin.h @@ -34,7 +34,7 @@ class DummyPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: void registerTypes(const char *uri); diff --git a/tests/manual/qmlplugindump/tests/dumper/Imports/imports_plugin.h b/tests/manual/qmlplugindump/tests/dumper/Imports/imports_plugin.h index 7c136dea30..fd09584d47 100644 --- a/tests/manual/qmlplugindump/tests/dumper/Imports/imports_plugin.h +++ b/tests/manual/qmlplugindump/tests/dumper/Imports/imports_plugin.h @@ -34,7 +34,7 @@ class ImportsPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: void registerTypes(const char *uri); diff --git a/tests/manual/qmlplugindump/tests/dumper/Versions/versions_plugin.h b/tests/manual/qmlplugindump/tests/dumper/Versions/versions_plugin.h index 91e9ce4174..4ba68a8125 100644 --- a/tests/manual/qmlplugindump/tests/dumper/Versions/versions_plugin.h +++ b/tests/manual/qmlplugindump/tests/dumper/Versions/versions_plugin.h @@ -34,7 +34,7 @@ class VersionsPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: void registerTypes(const char *uri); diff --git a/tests/manual/qmltypememory/TestPlugin/plugin.cpp b/tests/manual/qmltypememory/TestPlugin/plugin.cpp index ddc5430b43..d6cbf05a55 100644 --- a/tests/manual/qmltypememory/TestPlugin/plugin.cpp +++ b/tests/manual/qmltypememory/TestPlugin/plugin.cpp @@ -50,7 +50,7 @@ class TestType : public QObject class TestPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: void registerTypes(const char *uri) diff --git a/tests/manual/scenegraph_lancelot/data/text/textedit_multiline_selected_linebreaks_and_linewraps2.qml b/tests/manual/scenegraph_lancelot/data/text/textedit_multiline_selected_linebreaks_and_linewraps2.qml new file mode 100644 index 0000000000..c16bc9cdf7 --- /dev/null +++ b/tests/manual/scenegraph_lancelot/data/text/textedit_multiline_selected_linebreaks_and_linewraps2.qml @@ -0,0 +1,22 @@ +import QtQuick 2.0 + +Item { + width: 550 + height: 480 + + TextEdit { + id: textEdit + anchors.centerIn: parent + width: 550 + textFormat: TextEdit.RichText + text: "A<br /> + This is a long message to demenostrate a text selection issue. I need to type some more text here. This is line 3<br /> + This is a long message to demenostrate a text selection issue. I need to type some more text here. This is line 4" + wrapMode: TextEdit.Wrap + + Component.onCompleted: { + textEdit.selectAll() + } + } + +} diff --git a/tools/qmlimportscanner/main.cpp b/tools/qmlimportscanner/main.cpp index dcb9709bb8..2569d78c63 100644 --- a/tools/qmlimportscanner/main.cpp +++ b/tools/qmlimportscanner/main.cpp @@ -157,24 +157,46 @@ QVariantMap pluginsForModulePath(const QString &modulePath) { // Search for a given qml import in g_qmlImportPaths. QString resolveImportPath(const QString &uri, const QString &version) { - // Create path from uri (QtQuick.Controls -> QtQuick/Controls) - QString path = uri; - path.replace(QLatin1Char('.'), QLatin1Char('/')); - // search for the most spesifc version first - QString versionedName = path + QLatin1Char('.') + version; + const QLatin1Char dot('.'); + const QLatin1Char slash('/'); + const QStringList parts = uri.split(dot, QString::SkipEmptyParts); + + QString ver = version; while (true) { - // look in all g_qmlImportPaths foreach (const QString &qmlImportPath, g_qmlImportPaths) { - QString candidatePath = QDir::cleanPath(qmlImportPath + QLatin1Char('/') + versionedName); - if (QDir(candidatePath).exists()) - return candidatePath; // import found + // Search for the most specific version first, and search + // also for the version in parent modules. For example: + // - qml/QtQml/Models.2.0 + // - qml/QtQml.2.0/Models + // - qml/QtQml/Models.2 + // - qml/QtQml.2/Models + // - qml/QtQml/Models + if (ver.isEmpty()) { + const QString candidatePath = QDir::cleanPath(qmlImportPath + slash + parts.join(slash)); + if (QDir(candidatePath).exists()) + return candidatePath; // import found + } else { + for (int index = parts.count() - 1; index >= 0; --index) { + const QString candidatePath = QDir::cleanPath(qmlImportPath + slash + + parts.mid(0, index + 1).join(slash) + + dot + ver + slash + + parts.mid(index + 1).join(slash)); + + if (QDir(candidatePath).exists()) + return candidatePath; // import found + } + } } // remove the last version digit; stop if there are none left - int lastDot = versionedName.lastIndexOf(QLatin1Char('.')); - if (lastDot == -1) + if (ver.isEmpty()) break; - versionedName = versionedName.mid(0, lastDot); + + int lastDot = ver.lastIndexOf(dot); + if (lastDot == -1) + ver.clear(); + else + ver = ver.mid(0, lastDot); } return QString(); // not found diff --git a/tools/qmlplugindump/Info.plist b/tools/qmlplugindump/Info.plist index f35846d048..e6c4914ca0 100644 --- a/tools/qmlplugindump/Info.plist +++ b/tools/qmlplugindump/Info.plist @@ -5,11 +5,11 @@ <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleSignature</key> - <string>@TYPEINFO@</string> + <string>????</string> <key>CFBundleExecutable</key> - <string>@EXECUTABLE@</string> + <string>qmlplugindump</string> <key>CFBundleIdentifier</key> - <string>com.nokia.qt.qmlplugindump</string> + <string>org.qt-project.qt.qmlplugindump</string> <key>LSUIElement</key> <string>1</string> </dict> diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp index 7870e3a9df..d0d70fd0fe 100644 --- a/tools/qmlplugindump/main.cpp +++ b/tools/qmlplugindump/main.cpp @@ -771,7 +771,7 @@ static bool readDependenciesData(QString dependenciesFile, const QByteArray &fil QString version = obj.value(QStringLiteral("version")).toString(); if (name.isEmpty() || urisToSkip.contains(name) || version.isEmpty()) continue; - if (name.endsWith(QLatin1String("Private"))) { + if (name.endsWith(QLatin1String("Private"), Qt::CaseInsensitive)) { if (verbose) std::cerr << "skipping private dependecy " << qPrintable( name ) << " " << qPrintable(version) << std::endl; |