From 0944ff26223bd2c809025c9f42bc9935213f0d43 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 25 Jul 2019 16:37:43 +0200 Subject: Doc: Fix QtQuick.Shapes::ShapePath::strokeWidth property type Fixes: QTBUG-73541 Change-Id: Icb15cee3c49f142ef3634e35427dbbc0b9a2183e Reviewed-by: Laszlo Agocs --- src/quickshapes/qquickshape.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quickshapes/qquickshape.cpp b/src/quickshapes/qquickshape.cpp index 74cbf52a95..0ae16313ca 100644 --- a/src/quickshapes/qquickshape.cpp +++ b/src/quickshapes/qquickshape.cpp @@ -200,7 +200,7 @@ void QQuickShapePath::setStrokeColor(const QColor &color) } /*! - \qmlproperty color QtQuick.Shapes::ShapePath::strokeWidth + \qmlproperty real QtQuick.Shapes::ShapePath::strokeWidth This property holds the stroke width. -- cgit v1.2.3 From dfc6dc1d94a729f701172861a196b4b34bcd7518 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 30 Jul 2019 14:14:50 +0200 Subject: Fix possible crash with top/bottom aligned images An image inside at the end of a text block which did not start at text position 0 would resolve to an invalid QTextLine, since we passed the document position to lineForTextPosition(), which expects the relative block position. If the image was aligned to top or bottom, so that the extracted QTextLine was actually accessed, this would cause a crash. [ChangeLog][QtQuick][Text] Fixed a bug where aligning an image to "top" or "bottom" could cause a crash under certain circumstances. Task-number: QTBUG-77217 Change-Id: Iaa239ba482f2a765703656e4116cbebb8435a66e Reviewed-by: Simon Hausmann --- src/quick/items/qquicktextnodeengine.cpp | 2 +- .../qquicktext/data/verticallyAlignedImageInTable.qml | 14 ++++++++++++++ tests/auto/quick/qquicktext/tst_qquicktext.cpp | 14 ++++++++++++++ .../data/text/text_table_vertically_aligned_image.qml | 14 ++++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 tests/auto/quick/qquicktext/data/verticallyAlignedImageInTable.qml create mode 100644 tests/manual/scenegraph_lancelot/data/text/text_table_vertically_aligned_image.qml diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp index 36fc168ec2..5a4ef2b686 100644 --- a/src/quick/items/qquicktextnodeengine.cpp +++ b/src/quick/items/qquicktextnodeengine.cpp @@ -477,7 +477,7 @@ void QQuickTextNodeEngine::addTextObject(const QTextBlock &block, const QPointF } qreal ascent; - QTextLine line = block.layout()->lineForTextPosition(pos); + QTextLine line = block.layout()->lineForTextPosition(pos - block.position()); switch (format.verticalAlignment()) { case QTextCharFormat::AlignTop: diff --git a/tests/auto/quick/qquicktext/data/verticallyAlignedImageInTable.qml b/tests/auto/quick/qquicktext/data/verticallyAlignedImageInTable.qml new file mode 100644 index 0000000000..4c00362d15 --- /dev/null +++ b/tests/auto/quick/qquicktext/data/verticallyAlignedImageInTable.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 + +Item { + width: 320 + height: 480 + + Text { + anchors.centerIn: parent + font.family: "Arial" + font.pixelSize: 16 + textFormat: Text.RichText + text: "
" + } +} diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp index a9c35e0cc4..eafa6cb052 100644 --- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp +++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp @@ -161,6 +161,8 @@ private slots: void initialContentHeight(); + void verticallyAlignedImageInTable(); + private: QStringList standard; QStringList richText; @@ -4414,6 +4416,18 @@ void tst_qquicktext::implicitSizeChangeRewrap() QVERIFY(text->contentWidth() < window->width()); } +void tst_qquicktext::verticallyAlignedImageInTable() +{ + QScopedPointer window(new QQuickView); + window->setSource(testFileUrl("verticallyAlignedImageInTable.qml")); + QTRY_COMPARE(window->status(), QQuickView::Ready); + + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + // Don't crash +} + QTEST_MAIN(tst_qquicktext) #include "tst_qquicktext.moc" diff --git a/tests/manual/scenegraph_lancelot/data/text/text_table_vertically_aligned_image.qml b/tests/manual/scenegraph_lancelot/data/text/text_table_vertically_aligned_image.qml new file mode 100644 index 0000000000..d712f94572 --- /dev/null +++ b/tests/manual/scenegraph_lancelot/data/text/text_table_vertically_aligned_image.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 + +Item { + width: 320 + height: 480 + + Text { + anchors.centerIn: parent + font.family: "Arial" + font.pixelSize: 16 + textFormat: Text.RichText + text: "
" + } +} -- cgit v1.2.3 From 0647df8c88d4eaeedd19456b6e382308208e2be1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Bornemann?= Date: Fri, 2 Aug 2019 11:03:06 +0000 Subject: Revert "Yield error if qtquickcompiler is used in non-QML projects" This reverts commit c5578b16d6454e708c8ce12661a85d41eeaaa758, because it prevents enabling the qtquickcompiler feature globally. Fixes: QTBUG-77277 Change-Id: Ic80835c462570a67ae3105bb3d1b6452800d2c94 Reviewed-by: Kai Koehne --- tools/qmlcachegen/qtquickcompiler.prf | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tools/qmlcachegen/qtquickcompiler.prf b/tools/qmlcachegen/qtquickcompiler.prf index 967d55a5bd..b98d8a0198 100644 --- a/tools/qmlcachegen/qtquickcompiler.prf +++ b/tools/qmlcachegen/qtquickcompiler.prf @@ -1,15 +1,5 @@ if(qtc_run|lupdate_run): return() -!contains(QT, qml) { - qt_modules = \ - $$replace(QT, -private$, _private) \ - $$replace(QT_PRIVATE, -private$, _private) - qt_modules = $$resolve_depends(qt_modules, "QT.", ".depends" ".run_depends") - !contains(qt_modules, qml): \ - error("The qtquickcompiler feature cannot be used without the QML module.") - unset(qt_modules) -} - qtPrepareTool(QML_CACHEGEN, qmlcachegen, _FILTER) qtPrepareTool(QMAKE_RCC, rcc, _DEP) -- cgit v1.2.3 From ffda7180f3c11c35699ba8aa1a16efc6ee962e02 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Tue, 6 Aug 2019 09:51:02 +0200 Subject: tst_qquicklistview: make addOnCompleted more robust + sanity check Check that after we could not find an element, we do not suddenly find one afterwards. Moreover, disable the cacheBuffer as the asynchronous creation might cause issues, leading to the flakyness observed in QTBUG-77330 Task-number: QTBUG-77330 Change-Id: I444eede16a99a75340a0b7ccf17193298730a675 Reviewed-by: Simon Hausmann --- tests/auto/quick/qquicklistview/data/addoncompleted.qml | 3 +++ tests/auto/quick/qquicklistview/tst_qquicklistview.cpp | 1 + 2 files changed, 4 insertions(+) diff --git a/tests/auto/quick/qquicklistview/data/addoncompleted.qml b/tests/auto/quick/qquicklistview/data/addoncompleted.qml index 57265cb2c0..2341295868 100644 --- a/tests/auto/quick/qquicklistview/data/addoncompleted.qml +++ b/tests/auto/quick/qquicklistview/data/addoncompleted.qml @@ -73,6 +73,9 @@ Rectangle { anchors.fill: parent model: listModel objectName: "view" + // buffered delegates are created asynchronously + // therefore we disable buffering + cacheBuffer: 0 delegate: Rectangle { height: 15 diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index 127c873bbb..b896418de0 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -8956,6 +8956,7 @@ void tst_QQuickListView::addOnCompleted() y = 9999999; } else { const qreal newY = item->y(); + QVERIFY(newY != 9999999); // once we could not find an item, we shouldn' find any further ones QVERIFY2(newY > y, objName.toUtf8().constData()); y = newY; } -- cgit v1.2.3 From d4e1f5395c896dc5bda9a2e122e2ed0f45be6c18 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 8 Jul 2019 18:23:38 +0200 Subject: Use QSH::mouseDoubleClickDistance() and touchDoubleTapDistance() ... in documentation links and in implementation, now that they have been added. The doc links to QPlatformTheme::MouseDoubleClickDistance and QPlatformTheme::TouchDoubleTapDistance were dead ends because of those being private; and user code needed a way to read the values. So now there is new API in QStyleHints. Fixes: QTBUG-76944 Change-Id: I86bce4c7fe08c9da33745a4eed450757b3a30b03 Reviewed-by: Paul Wicking --- src/quick/handlers/qquicktaphandler.cpp | 16 +++++++--------- src/quick/items/qquickwindow.cpp | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/quick/handlers/qquicktaphandler.cpp b/src/quick/handlers/qquicktaphandler.cpp index 255e47d73a..a10064a665 100644 --- a/src/quick/handlers/qquicktaphandler.cpp +++ b/src/quick/handlers/qquicktaphandler.cpp @@ -78,8 +78,8 @@ int QQuickTapHandler::m_touchMultiTapDistanceSquared(-1); \l gesturePolicy to \c TapHandler.ReleaseWithinBounds. For multi-tap gestures (double-tap, triple-tap etc.), the distance moved - must not exceed QPlatformTheme::MouseDoubleClickDistance with mouse and - QPlatformTheme::TouchDoubleTapDistance with touch, and the time between + must not exceed QStyleHints::mouseDoubleClickDistance() with mouse and + QStyleHints::touchDoubleTapDistance() with touch, and the time between taps must not exceed QStyleHints::mouseDoubleClickInterval(). \sa MouseArea @@ -90,11 +90,9 @@ QQuickTapHandler::QQuickTapHandler(QQuickItem *parent) { if (m_mouseMultiClickDistanceSquared < 0) { m_multiTapInterval = qApp->styleHints()->mouseDoubleClickInterval() / 1000.0; - m_mouseMultiClickDistanceSquared = QGuiApplicationPrivate::platformTheme()-> - themeHint(QPlatformTheme::MouseDoubleClickDistance).toInt(); + m_mouseMultiClickDistanceSquared = qApp->styleHints()->mouseDoubleClickDistance(); m_mouseMultiClickDistanceSquared *= m_mouseMultiClickDistanceSquared; - m_touchMultiTapDistanceSquared = QGuiApplicationPrivate::platformTheme()-> - themeHint(QPlatformTheme::TouchDoubleTapDistance).toInt(); + m_touchMultiTapDistanceSquared = qApp->styleHints()->touchDoubleTapDistance(); m_touchMultiTapDistanceSquared *= m_touchMultiTapDistanceSquared; } } @@ -410,9 +408,9 @@ void QQuickTapHandler::updateTimeHeld() \since 5.11 This signal is emitted when the \c parent Item is tapped twice within a - short span of time (QStyleHints::mouseDoubleClickInterval) and distance - (QPlatformTheme::MouseDoubleClickDistance or - QPlatformTheme::TouchDoubleTapDistance). This signal always occurs after + short span of time (QStyleHints::mouseDoubleClickInterval()) and distance + (QStyleHints::mouseDoubleClickDistance() or + QStyleHints::touchDoubleTapDistance()). This signal always occurs after \l singleTapped, \l tapped, and \l tapCountChanged. The \c eventPoint signal parameter contains information from the release event about the point that was tapped. diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index acd5c4c077..79db297df8 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -702,7 +702,7 @@ bool QQuickWindowPrivate::checkIfDoubleTapped(ulong newPressEventTimestamp, QPoi if (touchMousePressTimestamp > 0) { QPoint distanceBetweenPresses = newPressPos - touchMousePressPos; - const int doubleTapDistance = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::TouchDoubleTapDistance).toInt(); + const int doubleTapDistance = QGuiApplication::styleHints()->touchDoubleTapDistance(); doubleClicked = (qAbs(distanceBetweenPresses.x()) <= doubleTapDistance) && (qAbs(distanceBetweenPresses.y()) <= doubleTapDistance); if (doubleClicked) { -- cgit v1.2.3 From bef4800768ca42003fabb117448500dabb5d795d Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Thu, 8 Aug 2019 13:43:22 +0200 Subject: Blacklist tst_qquicktextedit::mouseSelection in openSuse leap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This autotest is blacklisted as it is deemed flaky. Task-number: QTBUG-77389 Change-Id: I3561c98f0248507755f99fd7b6fe24c3d24cb522 Reviewed-by: Alexandru Croitor Reviewed-by: Jan Arve Sæther --- tests/auto/quick/qquicktextedit/BLACKLIST | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tests/auto/quick/qquicktextedit/BLACKLIST diff --git a/tests/auto/quick/qquicktextedit/BLACKLIST b/tests/auto/quick/qquicktextedit/BLACKLIST new file mode 100644 index 0000000000..9df9c7d75a --- /dev/null +++ b/tests/auto/quick/qquicktextedit/BLACKLIST @@ -0,0 +1,2 @@ +[mouseSelection] +opensuse-leap -- cgit v1.2.3 From bc30f5e23fb8edecd564e692e16f531815a75aae Mon Sep 17 00:00:00 2001 From: Mikko Gronoff Date: Mon, 12 Aug 2019 08:27:19 +0300 Subject: scenegraph: fix error: 'QOffscreenSurface' does not name a type Change-Id: I41a8b30b316b038ed1e3910adb0254931f385a2a Reviewed-by: Laszlo Agocs --- src/quick/scenegraph/qsgrhisupport_p.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/quick/scenegraph/qsgrhisupport_p.h b/src/quick/scenegraph/qsgrhisupport_p.h index 48ad2f05ae..0e1881aa00 100644 --- a/src/quick/scenegraph/qsgrhisupport_p.h +++ b/src/quick/scenegraph/qsgrhisupport_p.h @@ -86,6 +86,7 @@ QT_BEGIN_NAMESPACE class QSGDefaultRenderContext; class QVulkanInstance; +class QOffscreenSurface; // Opting in/out of QRhi and choosing the default/requested backend is managed // by this singleton. This is because this information may be needed before -- cgit v1.2.3 From f7156b7de9afc0949cf89d868023c875805df248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Tue, 6 Aug 2019 15:07:26 +0200 Subject: Skip perfMapFile test on Android qmljs is not available on Android, so we skip the test Change-Id: I93655fcbcaa405edf35846a93ef1467d651a62d7 Reviewed-by: Simon Hausmann --- tests/auto/qml/qv4assembler/tst_qv4assembler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp b/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp index 392ce16880..5dd8e9dcc0 100644 --- a/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp +++ b/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp @@ -59,7 +59,7 @@ void tst_QV4Assembler::initTestCase() void tst_QV4Assembler::perfMapFile() { -#if !defined(Q_OS_LINUX) +#if !defined(Q_OS_LINUX) || defined(Q_OS_ANDROID) QSKIP("perf map files are only generated on linux"); #else const QString qmljs = QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmljs"; -- cgit v1.2.3 From a9dad706a49444719c2c1a22867e9ef968841b1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Mon, 5 Aug 2019 13:27:16 +0200 Subject: Fix qqmlxmlhttprequest autotest for android TestHTTPServer needs to convert QUrl to QStrings while also keeping the resource information. (QUrl::toLocalFile() only converts to a local file.) Change-Id: I548a83f4db190efc89251a8335a52595829c5887 Task-number: QTBUG-73512 Reviewed-by: Simon Hausmann --- tests/auto/shared/testhttpserver.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/auto/shared/testhttpserver.cpp b/tests/auto/shared/testhttpserver.cpp index 09f16e8635..f0d5a89984 100644 --- a/tests/auto/shared/testhttpserver.cpp +++ b/tests/auto/shared/testhttpserver.cpp @@ -32,6 +32,7 @@ #include #include #include +#include /*! \internal @@ -152,17 +153,17 @@ bool TestHTTPServer::wait(const QUrl &expect, const QUrl &reply, const QUrl &bod m_state = AwaitingHeader; m_data.clear(); - QFile expectFile(expect.toLocalFile()); + QFile expectFile(QQmlFile::urlToLocalFileOrQrc(expect)); if (!expectFile.open(QIODevice::ReadOnly)) return false; - QFile replyFile(reply.toLocalFile()); + QFile replyFile(QQmlFile::urlToLocalFileOrQrc(reply)); if (!replyFile.open(QIODevice::ReadOnly)) return false; m_bodyData = QByteArray(); if (body.isValid()) { - QFile bodyFile(body.toLocalFile()); + QFile bodyFile(QQmlFile::urlToLocalFileOrQrc(body)); if (!bodyFile.open(QIODevice::ReadOnly)) return false; m_bodyData = bodyFile.readAll(); -- cgit v1.2.3 From d3e23c5125b64ac7ff2e75f8a83dcaf21d398f45 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Fri, 26 Jul 2019 16:57:05 +0200 Subject: Adapt usage of QMetaCallEvent to changes in QtCore Memory allocation is now handled by QMetaCallEvent. Change-Id: I78a2145af6cf93de5e9d71d6b943841f67183fa8 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlengine.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 9388df5617..20c8d53573 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -820,11 +820,12 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in QMetaMethod m = QMetaObjectPrivate::signal(object->metaObject(), index); QList parameterTypes = m.parameterTypes(); - int *types = (int *)malloc((parameterTypes.count() + 1) * sizeof(int)); - void **args = (void **) malloc((parameterTypes.count() + 1) *sizeof(void *)); + QScopedPointer ev(new QMetaCallEvent(m.methodIndex(), 0, nullptr, + object, index, + parameterTypes.count() + 1)); - types[0] = 0; // return type - args[0] = nullptr; // return value + void **args = ev->args(); + int *types = ev->types(); for (int ii = 0; ii < parameterTypes.count(); ++ii) { const QByteArray &typeName = parameterTypes.at(ii); @@ -837,21 +838,16 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in qWarning("QObject::connect: Cannot queue arguments of type '%s'\n" "(Make sure '%s' is registered using qRegisterMetaType().)", typeName.constData(), typeName.constData()); - free(types); - free(args); return; } args[ii + 1] = QMetaType::create(types[ii + 1], a[ii + 1]); } - QMetaCallEvent *ev = new QMetaCallEvent(m.methodIndex(), 0, nullptr, object, index, - parameterTypes.count() + 1, types, args); - QQmlThreadNotifierProxyObject *mpo = new QQmlThreadNotifierProxyObject; mpo->target = object; mpo->moveToThread(QObjectPrivate::get(object)->threadData->thread.loadAcquire()); - QCoreApplication::postEvent(mpo, ev); + QCoreApplication::postEvent(mpo, ev.take()); } else { QQmlNotifierEndpoint *ep = ddata->notify(index); -- cgit v1.2.3 From 3e86e35ad48d0e68eb65a1a65117a56cd8e0db40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Tue, 30 Jul 2019 16:26:42 +0200 Subject: Fix qqmltimer autotest for android Change-Id: I15967c6895e1a0c03d8aa279c2e78dc3f5318f01 Task-number: QTBUG-73512 Reviewed-by: Simon Hausmann --- tests/auto/qml/qqmltimer/dummy_imports.qml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/auto/qml/qqmltimer/dummy_imports.qml diff --git a/tests/auto/qml/qqmltimer/dummy_imports.qml b/tests/auto/qml/qqmltimer/dummy_imports.qml new file mode 100644 index 0000000000..f78e04d489 --- /dev/null +++ b/tests/auto/qml/qqmltimer/dummy_imports.qml @@ -0,0 +1,9 @@ +// This file exists for the sole purpose for qmlimportscanner to find +// which modules it needs to extract for deployment. +// Otherwise, it fails to find the imports that are expressed in the +// C++ code belonging to the test. + +import QtQml 2.0 +import QtQuick 2.0 + +QtObject { } // This is needed in order to keep importscanner happy -- cgit v1.2.3 From 4520862e9d4d46abb677d86d911e3092fea81a72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Tue, 30 Jul 2019 15:46:42 +0200 Subject: Fix qqmlpropertymap autotest for android Change-Id: I1734efcc2e7aa06185d1f713ecee63da9a7fc320 Task-number: QTBUG-73512 Reviewed-by: Simon Hausmann --- tests/auto/qml/qqmlpropertymap/dummy_imports.qml | 8 ++++++++ tests/auto/qml/qqmlpropertymap/qqmlpropertymap.pro | 2 ++ 2 files changed, 10 insertions(+) create mode 100644 tests/auto/qml/qqmlpropertymap/dummy_imports.qml diff --git a/tests/auto/qml/qqmlpropertymap/dummy_imports.qml b/tests/auto/qml/qqmlpropertymap/dummy_imports.qml new file mode 100644 index 0000000000..4ae9d3f2cf --- /dev/null +++ b/tests/auto/qml/qqmlpropertymap/dummy_imports.qml @@ -0,0 +1,8 @@ +// This file exists for the sole purpose for qmlimportscanner to find +// which modules it needs to extract for deployment. +// Otherwise, it fails to find the imports that are expressed in the +// C++ code belonging to the test. + +import QtQuick 2.0 + +QtObject { } // This is needed in order to keep importscanner happy diff --git a/tests/auto/qml/qqmlpropertymap/qqmlpropertymap.pro b/tests/auto/qml/qqmlpropertymap/qqmlpropertymap.pro index 8da300171d..b83e1e0da2 100644 --- a/tests/auto/qml/qqmlpropertymap/qqmlpropertymap.pro +++ b/tests/auto/qml/qqmlpropertymap/qqmlpropertymap.pro @@ -7,3 +7,5 @@ SOURCES += tst_qqmlpropertymap.cpp include (../../shared/util.pri) QT += core-private gui-private qml-private quick-private testlib + +TESTDATA = data/* -- cgit v1.2.3 From 1ec1a863471445132c1d29500d6ac720663887ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Fri, 26 Jul 2019 18:27:25 +0200 Subject: Fix qqmllanguage autotest on Android Mostly fixes to the usual resource paths. In addition, we now put the special file with UTF-8 I18nType?????.qml typename in a resource file on Android, which actually works. Task-number: QTBUG-73512 Change-Id: I1835b5d358c14fbb3f6dfc954de03594f7fed621 Reviewed-by: Simon Hausmann --- tests/auto/qml/qqmllanguage/qqmllanguage.pro | 2 + tests/auto/qml/qqmllanguage/qqmllanguage.qrc | 5 + tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 113 ++++++++++++++--------- 3 files changed, 75 insertions(+), 45 deletions(-) create mode 100644 tests/auto/qml/qqmllanguage/qqmllanguage.qrc diff --git a/tests/auto/qml/qqmllanguage/qqmllanguage.pro b/tests/auto/qml/qqmllanguage/qqmllanguage.pro index 3e88f3f0db..724a27320c 100644 --- a/tests/auto/qml/qqmllanguage/qqmllanguage.pro +++ b/tests/auto/qml/qqmllanguage/qqmllanguage.pro @@ -17,3 +17,5 @@ include (../../shared/util.pri) OTHER_FILES += \ data/readonlyObjectProperty.qml + +android: RESOURCES += qqmllanguage.qrc diff --git a/tests/auto/qml/qqmllanguage/qqmllanguage.qrc b/tests/auto/qml/qqmllanguage/qqmllanguage.qrc new file mode 100644 index 0000000000..f5212ac75c --- /dev/null +++ b/tests/auto/qml/qqmllanguage/qqmllanguage.qrc @@ -0,0 +1,5 @@ + + +data/I18nType30.qml + + diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index a54c4b35d4..27b550457d 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -370,7 +370,8 @@ private: void tst_qqmllanguage::cleanupTestCase() { - QVERIFY(QFile::remove(testFile(QString::fromUtf8("I18nType\303\201\303\242\303\243\303\244\303\245.qml")))); + if (dataDirectoryUrl().scheme() != QLatin1String("qrc")) + QVERIFY(QFile::remove(testFile(QString::fromUtf8("I18nType\303\201\303\242\303\243\303\244\303\245.qml")))); } void tst_qqmllanguage::insertedSemicolon_data() @@ -630,6 +631,18 @@ void tst_qqmllanguage::errors_data() void tst_qqmllanguage::errors() { +#ifdef Q_OS_ANDROID + if (qstrcmp(QTest::currentDataTag(), "fuzzed.2") == 0) { + QSKIP("Gives different errors on Android"); + /* Only gives one error on Android: + + qrc:/data/fuzzed.2.qml:1:1: " + import" + ^ + So, it seems to complain about the first import (which is understandable) + */ + } +#endif QFETCH(QString, file); QFETCH(QString, errorFile); QFETCH(bool, create); @@ -2678,11 +2691,15 @@ void tst_qqmllanguage::importsLocal_data() "Test {}" << (!qmlCheckTypes()?"TestType":"") << (!qmlCheckTypes()?"":"Test is ambiguous. Found in org/qtproject/Test/ and in subdir/"); - QTest::newRow("file URL survives percent-encoding") - << "import \"" + QUrl::fromLocalFile(QDir::currentPath() + "/{subdir}").toString() + "\"\n" - "Test {}" - << "QQuickRectangle" - << ""; + + if (dataDirectoryUrl().scheme() != QLatin1String("qrc")) { + // file URL doesn't work with qrc scheme + QTest::newRow("file URL survives percent-encoding") + << "import \"" + QUrl::fromLocalFile(QDir::currentPath() + "/{subdir}").toString() + "\"\n" + "Test {}" + << "QQuickRectangle" + << ""; + } } void tst_qqmllanguage::importsLocal() @@ -3441,7 +3458,11 @@ void tst_qqmllanguage::uncreatableTypesAsProperties() void tst_qqmllanguage::initTestCase() { QQmlDataTest::initTestCase(); - QVERIFY2(QDir::setCurrent(dataDirectory()), qPrintable("Could not chdir to " + dataDirectory())); + if (dataDirectoryUrl().scheme() == QLatin1String("qrc")) + engine.addImportPath(dataDirectory()); + else + QVERIFY2(QDir::setCurrent(dataDirectory()), qPrintable("Could not chdir to " + dataDirectory())); + defaultImportPathList = engine.importPathList(); @@ -3472,11 +3493,13 @@ void tst_qqmllanguage::initTestCase() // For POSIX, this will just be data/I18nType.qml, since POSIX is 7-bit // For iso8859-1 locale, this will just be data/I18nType?????.qml where ????? is 5 8-bit characters // For utf-8 locale, this will be data/I18nType??????????.qml where ?????????? is 5 8-bit characters, UTF-8 encoded - QFile in(testFileUrl(QLatin1String("I18nType30.qml")).toLocalFile()); - QVERIFY2(in.open(QIODevice::ReadOnly), qPrintable(QString::fromLatin1("Cannot open '%1': %2").arg(in.fileName(), in.errorString()))); - QFile out(testFileUrl(QString::fromUtf8("I18nType\303\201\303\242\303\243\303\244\303\245.qml")).toLocalFile()); - QVERIFY2(out.open(QIODevice::WriteOnly), qPrintable(QString::fromLatin1("Cannot open '%1': %2").arg(out.fileName(), out.errorString()))); - out.write(in.readAll()); + if (dataDirectoryUrl().scheme() != QLatin1String("qrc")) { + QFile in(testFileUrl(QLatin1String("I18nType30.qml")).toLocalFile()); + QVERIFY2(in.open(QIODevice::ReadOnly), qPrintable(QString::fromLatin1("Cannot open '%1': %2").arg(in.fileName(), in.errorString()))); + QFile out(testFileUrl(QString::fromUtf8("I18nType\303\201\303\242\303\243\303\244\303\245.qml")).toLocalFile()); + QVERIFY2(out.open(QIODevice::WriteOnly), qPrintable(QString::fromLatin1("Cannot open '%1': %2").arg(out.fileName(), out.errorString()))); + out.write(in.readAll()); + } // Register a Composite Singleton. qmlRegisterSingletonType(testFileUrl("singleton/RegisteredCompositeSingletonType.qml"), "org.qtproject.Test", 1, 0, "RegisteredSingleton"); @@ -3988,7 +4011,7 @@ void tst_qqmllanguage::objectDeletionNotify() void tst_qqmllanguage::scopedProperties() { - QQmlComponent component(&engine, testFile("scopedProperties.qml")); + QQmlComponent component(&engine, testFileUrl("scopedProperties.qml")); QScopedPointer o(component.create()); QVERIFY(o != nullptr); @@ -3997,7 +4020,7 @@ void tst_qqmllanguage::scopedProperties() void tst_qqmllanguage::deepProperty() { - QQmlComponent component(&engine, testFile("deepProperty.qml")); + QQmlComponent component(&engine, testFileUrl("deepProperty.qml")); QScopedPointer o(component.create()); QVERIFY(o != nullptr); QFont font = qvariant_cast(qvariant_cast(o->property("someObject"))->property("font")); @@ -4015,7 +4038,7 @@ void tst_qqmllanguage::implicitImportsLast() if (engine.importPathList() == defaultImportPathList) engine.addImportPath(testFile("lib")); - QQmlComponent component(&engine, testFile("localOrderTest.qml")); + QQmlComponent component(&engine, testFileUrl("localOrderTest.qml")); VERIFY_ERRORS(0); QScopedPointer object(component.create()); QVERIFY(object != nullptr); @@ -4035,7 +4058,7 @@ void tst_qqmllanguage::getSingletonInstance(QQmlEngine& engine, const char* file if (!fileName || !propertyName) return; - QQmlComponent component(&engine, testFile(fileName)); + QQmlComponent component(&engine, testFileUrl(fileName)); VERIFY_ERRORS(0); QScopedPointer object(component.create()); QVERIFY(object != nullptr); @@ -4077,7 +4100,7 @@ void verifyCompositeSingletonPropertyValues(QObject* o, const char* n1, int v1, // Reads values from a composite singleton type void tst_qqmllanguage::compositeSingletonProperties() { - QQmlComponent component(&engine, testFile("singletonTest1.qml")); + QQmlComponent component(&engine, testFileUrl("singletonTest1.qml")); VERIFY_ERRORS(0); QScopedPointer o(component.create()); QVERIFY(o != nullptr); @@ -4124,14 +4147,14 @@ void tst_qqmllanguage::compositeSingletonDifferentEngine() // pragma Singleton in a non-type qml file fails void tst_qqmllanguage::compositeSingletonNonTypeError() { - QQmlComponent component(&engine, testFile("singletonTest4.qml")); + QQmlComponent component(&engine, testFileUrl("singletonTest4.qml")); VERIFY_ERRORS("singletonTest4.error.txt"); } // Loads the singleton using a namespace qualifier void tst_qqmllanguage::compositeSingletonQualifiedNamespace() { - QQmlComponent component(&engine, testFile("singletonTest5.qml")); + QQmlComponent component(&engine, testFileUrl("singletonTest5.qml")); VERIFY_ERRORS(0); QScopedPointer o(component.create()); QVERIFY(o != nullptr); @@ -4156,7 +4179,7 @@ void tst_qqmllanguage::compositeSingletonModule() { engine.addImportPath(testFile("singleton/module")); - QQmlComponent component(&engine, testFile("singletonTest6.qml")); + QQmlComponent component(&engine, testFileUrl("singletonTest6.qml")); VERIFY_ERRORS(0); QScopedPointer o(component.create()); QVERIFY(o != nullptr); @@ -4182,7 +4205,7 @@ void tst_qqmllanguage::compositeSingletonModuleVersioned() { engine.addImportPath(testFile("singleton/module")); - QQmlComponent component(&engine, testFile("singletonTest7.qml")); + QQmlComponent component(&engine, testFileUrl("singletonTest7.qml")); VERIFY_ERRORS(0); QScopedPointer o(component.create()); QVERIFY(o != nullptr); @@ -4208,7 +4231,7 @@ void tst_qqmllanguage::compositeSingletonModuleQualified() { engine.addImportPath(testFile("singleton/module")); - QQmlComponent component(&engine, testFile("singletonTest8.qml")); + QQmlComponent component(&engine, testFileUrl("singletonTest8.qml")); VERIFY_ERRORS(0); QScopedPointer o(component.create()); QVERIFY(o != nullptr); @@ -4232,14 +4255,14 @@ void tst_qqmllanguage::compositeSingletonModuleQualified() // Tries to instantiate a type with a pragma Singleton and fails void tst_qqmllanguage::compositeSingletonInstantiateError() { - QQmlComponent component(&engine, testFile("singletonTest9.qml")); + QQmlComponent component(&engine, testFileUrl("singletonTest9.qml")); VERIFY_ERRORS("singletonTest9.error.txt"); } // Having a composite singleton type as dynamic property type is allowed void tst_qqmllanguage::compositeSingletonDynamicPropertyError() { - QQmlComponent component(&engine, testFile("singletonTest10.qml")); + QQmlComponent component(&engine, testFileUrl("singletonTest10.qml")); VERIFY_ERRORS(0); } @@ -4247,7 +4270,7 @@ void tst_qqmllanguage::compositeSingletonDynamicPropertyError() // (like C++ singleton) void tst_qqmllanguage::compositeSingletonDynamicSignal() { - QQmlComponent component(&engine, testFile("singletonTest11.qml")); + QQmlComponent component(&engine, testFileUrl("singletonTest11.qml")); VERIFY_ERRORS(0); QScopedPointer o(component.create()); QVERIFY(o != nullptr); @@ -4261,21 +4284,21 @@ void tst_qqmllanguage::compositeSingletonQmlRegisterTypeError() { qmlRegisterType(testFileUrl("singleton/registeredComposite/CompositeType.qml"), "CompositeSingletonTest", 1, 0, "RegisteredCompositeType"); - QQmlComponent component(&engine, testFile("singletonTest12.qml")); + QQmlComponent component(&engine, testFileUrl("singletonTest12.qml")); VERIFY_ERRORS("singletonTest12.error.txt"); } // Qmldir defines a type as a singleton, but the qml file does not have a pragma Singleton. void tst_qqmllanguage::compositeSingletonQmldirNoPragmaError() { - QQmlComponent component(&engine, testFile("singletonTest13.qml")); + QQmlComponent component(&engine, testFileUrl("singletonTest13.qml")); VERIFY_ERRORS("singletonTest13.error.txt"); } // Invalid singleton definition in the qmldir file results in an error void tst_qqmllanguage::compositeSingletonQmlDirError() { - QQmlComponent component(&engine, testFile("singletonTest14.qml")); + QQmlComponent component(&engine, testFileUrl("singletonTest14.qml")); VERIFY_ERRORS("singletonTest14.error.txt"); } @@ -4309,7 +4332,7 @@ void tst_qqmllanguage::compositeSingletonRemote() // the pragma Singleton changes. void tst_qqmllanguage::compositeSingletonJavaScriptPragma() { - QQmlComponent component(&engine, testFile("singletonTest16.qml")); + QQmlComponent component(&engine, testFileUrl("singletonTest16.qml")); VERIFY_ERRORS(0); QScopedPointer o(component.create()); QVERIFY(o != nullptr); @@ -4327,7 +4350,7 @@ void tst_qqmllanguage::compositeSingletonSelectors() QQmlEngine e2; QQmlFileSelector qmlSelector(&e2); qmlSelector.setExtraSelectors(QStringList() << "basicSelector"); - QQmlComponent component(&e2, testFile("singletonTest1.qml")); + QQmlComponent component(&e2, testFileUrl("singletonTest1.qml")); VERIFY_ERRORS(0); QScopedPointer o(component.create()); QVERIFY(o != nullptr); @@ -4339,7 +4362,7 @@ void tst_qqmllanguage::compositeSingletonSelectors() // qmlRegisterSingletonType. void tst_qqmllanguage::compositeSingletonRegistered() { - QQmlComponent component(&engine, testFile("singletonTest17.qml")); + QQmlComponent component(&engine, testFileUrl("singletonTest17.qml")); VERIFY_ERRORS(0); QScopedPointer o(component.create()); QVERIFY(o != nullptr); @@ -4349,7 +4372,7 @@ void tst_qqmllanguage::compositeSingletonRegistered() void tst_qqmllanguage::compositeSingletonCircular() { - QQmlComponent component(&engine, testFile("circularSingleton.qml")); + QQmlComponent component(&engine, testFileUrl("circularSingleton.qml")); VERIFY_ERRORS(0); QQmlTestMessageHandler messageHandler; @@ -4383,7 +4406,7 @@ void tst_qqmllanguage::singletonsHaveContextAndEngine() void tst_qqmllanguage::customParserBindingScopes() { - QQmlComponent component(&engine, testFile("customParserBindingScopes.qml")); + QQmlComponent component(&engine, testFileUrl("customParserBindingScopes.qml")); VERIFY_ERRORS(0); QScopedPointer o(component.create()); QVERIFY(!o.isNull()); @@ -4394,7 +4417,7 @@ void tst_qqmllanguage::customParserBindingScopes() void tst_qqmllanguage::customParserEvaluateEnum() { - QQmlComponent component(&engine, testFile("customParserEvaluateEnum.qml")); + QQmlComponent component(&engine, testFileUrl("customParserEvaluateEnum.qml")); VERIFY_ERRORS(0); QScopedPointer o(component.create()); QVERIFY(!o.isNull()); @@ -4402,7 +4425,7 @@ void tst_qqmllanguage::customParserEvaluateEnum() void tst_qqmllanguage::customParserProperties() { - QQmlComponent component(&engine, testFile("customParserProperties.qml")); + QQmlComponent component(&engine, testFileUrl("customParserProperties.qml")); VERIFY_ERRORS(0); QScopedPointer o(component.create()); QVERIFY(!o.isNull()); @@ -4416,7 +4439,7 @@ void tst_qqmllanguage::customParserProperties() void tst_qqmllanguage::customParserWithExtendedObject() { - QQmlComponent component(&engine, testFile("customExtendedParserProperties.qml")); + QQmlComponent component(&engine, testFileUrl("customExtendedParserProperties.qml")); VERIFY_ERRORS(0); QScopedPointer o(component.create()); QVERIFY(!o.isNull()); @@ -4434,7 +4457,7 @@ void tst_qqmllanguage::customParserWithExtendedObject() void tst_qqmllanguage::nestedCustomParsers() { - QQmlComponent component(&engine, testFile("nestedCustomParsers.qml")); + QQmlComponent component(&engine, testFileUrl("nestedCustomParsers.qml")); VERIFY_ERRORS(0); QScopedPointer o(component.create()); QVERIFY(!o.isNull()); @@ -4448,7 +4471,7 @@ void tst_qqmllanguage::nestedCustomParsers() void tst_qqmllanguage::preservePropertyCacheOnGroupObjects() { - QQmlComponent component(&engine, testFile("preservePropertyCacheOnGroupObjects.qml")); + QQmlComponent component(&engine, testFileUrl("preservePropertyCacheOnGroupObjects.qml")); VERIFY_ERRORS(0); QScopedPointer o(component.create()); QVERIFY(!o.isNull()); @@ -4467,7 +4490,7 @@ void tst_qqmllanguage::preservePropertyCacheOnGroupObjects() void tst_qqmllanguage::propertyCacheInSync() { - QQmlComponent component(&engine, testFile("propertyCacheInSync.qml")); + QQmlComponent component(&engine, testFileUrl("propertyCacheInSync.qml")); VERIFY_ERRORS(0); QScopedPointer o(component.create()); QVERIFY(!o.isNull()); @@ -4487,7 +4510,7 @@ void tst_qqmllanguage::propertyCacheInSync() void tst_qqmllanguage::rootObjectInCreationNotForSubObjects() { - QQmlComponent component(&engine, testFile("rootObjectInCreationNotForSubObjects.qml")); + QQmlComponent component(&engine, testFileUrl("rootObjectInCreationNotForSubObjects.qml")); VERIFY_ERRORS(0); QScopedPointer o(component.create()); QVERIFY(!o.isNull()); @@ -4513,7 +4536,7 @@ void tst_qqmllanguage::rootObjectInCreationNotForSubObjects() // QTBUG-63036 void tst_qqmllanguage::lazyDeferredSubObject() { - QQmlComponent component(&engine, testFile("lazyDeferredSubObject.qml")); + QQmlComponent component(&engine, testFileUrl("lazyDeferredSubObject.qml")); VERIFY_ERRORS(0); QScopedPointer object(component.create()); QVERIFY(!object.isNull()); @@ -4528,7 +4551,7 @@ void tst_qqmllanguage::lazyDeferredSubObject() // QTBUG-63200 void tst_qqmllanguage::deferredProperties() { - QQmlComponent component(&engine, testFile("deferredProperties.qml")); + QQmlComponent component(&engine, testFileUrl("deferredProperties.qml")); VERIFY_ERRORS(0); QScopedPointer object(component.create()); QVERIFY(!object.isNull()); @@ -4645,7 +4668,7 @@ static void testExecuteDeferredOnce(const QQmlProperty &property) void tst_qqmllanguage::executeDeferredPropertiesOnce() { - QQmlComponent component(&engine, testFile("deferredProperties.qml")); + QQmlComponent component(&engine, testFileUrl("deferredProperties.qml")); VERIFY_ERRORS(0); QScopedPointer object(component.create()); QVERIFY(!object.isNull()); @@ -4745,7 +4768,7 @@ void tst_qqmllanguage::deleteSingletons() QPointer singleton; { QQmlEngine tmpEngine; - QQmlComponent component(&tmpEngine, testFile("singletonTest5.qml")); + QQmlComponent component(&tmpEngine, testFileUrl("singletonTest5.qml")); VERIFY_ERRORS(0); QScopedPointer o(component.create()); QVERIFY(o != nullptr); @@ -4772,7 +4795,7 @@ void tst_qqmllanguage::arrayBuffer_data() void tst_qqmllanguage::arrayBuffer() { QFETCH(QString, file); - QQmlComponent component(&engine, testFile(file)); + QQmlComponent component(&engine, testFileUrl(file)); VERIFY_ERRORS(0); QScopedPointer object(component.create()); QVERIFY(object != nullptr); -- cgit v1.2.3 From e9bd94065de79342a64a83db4014928fe86f2e63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Thu, 1 Aug 2019 14:44:05 +0200 Subject: Fix qqmlvaluetypes autotest for android The test assumed that QFont::pixelSize always retured -1. QFont::pointSizeF might also be -1. Change-Id: Ia00ecdd897fc15de533bdfb34716d568c5c4c6c2 Task-number: QTBUG-73512 Reviewed-by: Simon Hausmann --- tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp index 83a37df797..8a602a0356 100644 --- a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp +++ b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp @@ -784,6 +784,7 @@ void tst_qqmlvaluetypes::font() { QQmlComponent component(&engine, testFileUrl("font_read.qml")); MyTypeObject *object = qobject_cast(component.create()); + QVERIFY2(component.isReady(), qPrintable(component.errorString())); QVERIFY(object != nullptr); QCOMPARE(object->property("f_family").toString(), object->font().family()); @@ -793,8 +794,19 @@ void tst_qqmlvaluetypes::font() QCOMPARE(object->property("f_underline").toBool(), object->font().underline()); QCOMPARE(object->property("f_overline").toBool(), object->font().overline()); QCOMPARE(object->property("f_strikeout").toBool(), object->font().strikeOut()); - QCOMPARE(object->property("f_pointSize").toDouble(), object->font().pointSizeF()); - QCOMPARE(object->property("f_pixelSize").toInt(), int((object->font().pointSizeF() * qt_defaultDpi()) / qreal(72.))); + + // If QFont::pixelSize() was set, QFont::pointSizeF() would return -1. + // If QFont::pointSizeF() was set, QFont::pixelSize() would return -1. + // QQuickFontValueType doesn't follow this semantic (if its -1 it calculates the value of + // the property from the other one) + double expectedPointSizeF = object->font().pointSizeF(); + if (expectedPointSizeF == -1) expectedPointSizeF = object->font().pixelSize() * qreal(72.) / qreal(qt_defaultDpi()); + int expectedPixelSize = object->font().pixelSize(); + if (expectedPixelSize == -1) expectedPixelSize = int((object->font().pointSizeF() * qt_defaultDpi()) / qreal(72.)); + + QCOMPARE(object->property("f_pointSize").toDouble(), expectedPointSizeF); + QCOMPARE(object->property("f_pixelSize").toInt(), expectedPixelSize); + QCOMPARE(object->property("f_capitalization").toInt(), (int)object->font().capitalization()); QCOMPARE(object->property("f_letterSpacing").toDouble(), object->font().letterSpacing()); QCOMPARE(object->property("f_wordSpacing").toDouble(), object->font().wordSpacing()); -- cgit v1.2.3 From 07ea03a8a24947e368bdf529a6fe5c0c8f6429eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Tue, 30 Jul 2019 15:53:58 +0200 Subject: Fix qqmlsqldatabase autotest for android Change-Id: Ide59a86edbef87ccde83160c50f3e27dbc06e890 Task-number: QTBUG-73512 Reviewed-by: Simon Hausmann --- tests/auto/qml/qqmlsqldatabase/dummy_imports.qml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 tests/auto/qml/qqmlsqldatabase/dummy_imports.qml diff --git a/tests/auto/qml/qqmlsqldatabase/dummy_imports.qml b/tests/auto/qml/qqmlsqldatabase/dummy_imports.qml new file mode 100644 index 0000000000..4ae9d3f2cf --- /dev/null +++ b/tests/auto/qml/qqmlsqldatabase/dummy_imports.qml @@ -0,0 +1,8 @@ +// This file exists for the sole purpose for qmlimportscanner to find +// which modules it needs to extract for deployment. +// Otherwise, it fails to find the imports that are expressed in the +// C++ code belonging to the test. + +import QtQuick 2.0 + +QtObject { } // This is needed in order to keep importscanner happy -- cgit v1.2.3 From f18fefc3ba74cc9da37843271f141388e98c7fc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Mon, 5 Aug 2019 21:58:38 +0200 Subject: Fix qquickfolderlistmodel autotest on Android Mostly resource path issues. It also seems to be some issues with the default folder of FolderListModel on Android. Change-Id: I8260775afd53bfe33977a9571d37009703774ae8 Task-number: QTBUG-77335 Task-number: QTBUG-73512 Reviewed-by: Mitch Curtis --- .../auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp b/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp index 4b2ae45bae..b7600351b7 100644 --- a/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp +++ b/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp @@ -112,6 +112,10 @@ void tst_qquickfolderlistmodel::initTestCase() void tst_qquickfolderlistmodel::basicProperties() { +#ifdef Q_OS_ANDROID + QSKIP("[QTBUG-77335] Initial folder of FolderListModel on Android does not work properly," + " and from there on it is unreliable to change the folder"); +#endif QQmlComponent component(&engine, testFileUrl("basic.qml")); checkNoErrors(component); @@ -356,6 +360,9 @@ void tst_qquickfolderlistmodel::showDotAndDotDot() void tst_qquickfolderlistmodel::showDotAndDotDot_data() { +#ifdef Q_OS_ANDROID + QSKIP("Resource file system does not list '.' and '..' due to QDir::entryList() behavior"); +#endif QTest::addColumn("folder"); QTest::addColumn("rootFolder"); QTest::addColumn("showDotAndDotDot"); @@ -411,7 +418,7 @@ void tst_qquickfolderlistmodel::sortCaseSensitive() QAbstractListModel *flm = qobject_cast(component.create()); QVERIFY(flm != 0); - flm->setProperty("folder", QUrl::fromLocalFile(dataDirectoryUrl().path() + QLatin1String("/sortdir"))); + flm->setProperty("folder", testFileUrl("sortdir")); flm->setProperty("sortCaseSensitive", sortCaseSensitive); QTRY_COMPARE(flm->property("count").toInt(), 2); // wait for refresh for (int i = 0; i < 2; ++i) -- cgit v1.2.3 From b70fcaa7ce9c9afa068679f67aa909c6de8992ff Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 13 Aug 2019 15:57:22 +0200 Subject: Minor cleanup and logic fix in basic renderloop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The (gl) condition is clearly an oversight, the branch should be taken if either gl or rhi are valid. Change-Id: Ieb0a9aeec996f8940716f9fdafe90525b60fc248 Reviewed-by: Christian Strømme --- src/quick/scenegraph/qsgrenderloop.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp index ec835fe3bd..db657cd7df 100644 --- a/src/quick/scenegraph/qsgrenderloop.cpp +++ b/src/quick/scenegraph/qsgrenderloop.cpp @@ -383,20 +383,23 @@ void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window) QQuickWindowPrivate *d = QQuickWindowPrivate::get(window); bool current = false; - if (gl) { - QSurface *surface = window; - // There may be no platform window if the window got closed. - if (!window->handle()) - surface = offscreenSurface; + if (gl || rhi) { if (rhi) { + // Direct OpenGL calls in user code need a current context, like + // when rendering; ensure this (no-op when not running on GL). + // Also works when there is no handle() anymore. rhi->makeThreadLocalNativeContextCurrent(); current = true; } else { + QSurface *surface = window; + // There may be no platform window if the window got closed. + if (!window->handle()) + surface = offscreenSurface; current = gl->makeCurrent(surface); } + if (Q_UNLIKELY(!current)) + qCDebug(QSG_LOG_RENDERLOOP, "cleanup without an OpenGL context"); } - if (Q_UNLIKELY(!current)) - qCDebug(QSG_LOG_RENDERLOOP, "cleanup without an OpenGL context"); #if QT_CONFIG(quick_shadereffect) QSGRhiShaderEffectNode::cleanupMaterialTypeCache(); -- cgit v1.2.3 From 88534c95375e9fdbf6d5411f07c78979fe1da825 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 12 Aug 2019 15:29:13 +0200 Subject: Enable threaded render loop for d3d11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I5772b38c59b8fe3f9a30f56d3a559f6161443562 Reviewed-by: Christian Strømme --- src/quick/scenegraph/qsgrenderloop.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp index db657cd7df..58dfd97e03 100644 --- a/src/quick/scenegraph/qsgrenderloop.cpp +++ b/src/quick/scenegraph/qsgrenderloop.cpp @@ -244,25 +244,28 @@ QSGRenderLoop *QSGRenderLoop::instance() } if (rhiSupport->isRhiEnabled()) { - // no 'windows' because that's not yet ported to the rhi - if (loopType == WindowsRenderLoop) - loopType = BasicRenderLoop; - switch (rhiSupport->rhiBackend()) { - case QRhi::D3D11: - // D3D11 is forced to 'basic' always for now. The threaded loop's model may - // not be suitable for DXGI due to the possibility of having the main - // thread blocked while issuing a Present. To be investigated. + case QRhi::Null: loopType = BasicRenderLoop; break; - case QRhi::Null: - loopType = BasicRenderLoop; + case QRhi::D3D11: + // The threaded loop's model may not be suitable for DXGI + // due to the possibility of having the main thread (with + // the Windows message pump) blocked while issuing a + // Present on the render thread. However, according to the + // docs this can be a problem for fullscreen swapchains + // only. So leave threaded enabled by default for now and + // revisit later if there are problems. break; default: break; } + + // no 'windows' because that's not yet ported to the rhi + if (loopType == WindowsRenderLoop) + loopType = BasicRenderLoop; } // The environment variables can always override. This is good -- cgit v1.2.3 From efe0bec9468d75b768d1e26d2a8b440ade5ba632 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 15 Aug 2019 15:19:31 +0200 Subject: Allow Connections to handle signals using JavaScript functions Requiring full function definitions as signal handlers has two advantages: 1, We don't need a custom parser that magically recognizes properties which would otherwise be an error in other components. 2, The user is forced to specify the full signature of the handler, including any parameters. This helps when the functions will eventually be compiled to C++ The old behavior is retained, generating a warning if any of the magic bindings are still set in a Connections element. Only if no magic bindings are found, the functions are connected. This is because there might be functions named onFoo in old-style Connections elements and silently connecting those to any matching signals would be a change in behavior. Change-Id: I8c78d8994fdcddd355fe822cde9a0702dc8c75de Reviewed-by: Fabian Kosmale Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlengine.cpp | 4 ++ src/qml/types/qqmlconnections.cpp | 72 +++++++++++++++++++++- src/qml/types/qqmlconnections_p.h | 4 ++ .../data/bindings/connection-no-signal-name.qml | 15 +++++ .../data/bindings/connection-targetchange.qml | 25 ++++++++ .../bindings/connection-unknownsignals-ignored.qml | 8 +++ .../connection-unknownsignals-notarget.qml | 5 ++ .../bindings/connection-unknownsignals-parent.qml | 5 ++ .../data/bindings/connection-unknownsignals.qml | 7 +++ .../data/bindings/disabled-at-start.qml | 14 +++++ .../data/bindings/override-proxy-type.qml | 13 ++++ .../data/bindings/rewriteError-global.qml | 8 +++ .../data/bindings/rewriteError-unnamed.qml | 8 +++ .../data/bindings/singletontype-target.qml | 22 +++++++ .../data/bindings/test-connection-implicit.qml | 9 +++ .../data/bindings/test-connection.qml | 10 +++ .../qml/qqmlconnections/data/bindings/trimming.qml | 10 +++ .../data/connection-no-signal-name.qml | 15 ----- .../data/connection-targetchange.qml | 25 -------- .../data/connection-unknownsignals-ignored.qml | 8 --- .../data/connection-unknownsignals-notarget.qml | 5 -- .../data/connection-unknownsignals-parent.qml | 5 -- .../data/connection-unknownsignals.qml | 7 --- .../qml/qqmlconnections/data/disabled-at-start.qml | 14 ----- .../data/functions/connection-no-signal-name.qml | 15 +++++ .../data/functions/connection-targetchange.qml | 25 ++++++++ .../connection-unknownsignals-ignored.qml | 17 +++++ .../connection-unknownsignals-notarget.qml | 9 +++ .../functions/connection-unknownsignals-parent.qml | 8 +++ .../data/functions/connection-unknownsignals.qml | 11 ++++ .../data/functions/disabled-at-start.qml | 14 +++++ .../data/functions/override-proxy-type.qml | 13 ++++ .../data/functions/rewriteError-global.qml | 8 +++ .../data/functions/rewriteError-unnamed.qml | 8 +++ .../data/functions/singletontype-target.qml | 22 +++++++ .../data/functions/test-connection-implicit.qml | 9 +++ .../data/functions/test-connection.qml | 14 +++++ .../qqmlconnections/data/functions/trimming.qml | 13 ++++ .../qqmlconnections/data/override-proxy-type.qml | 13 ---- .../qqmlconnections/data/rewriteError-global.qml | 8 --- .../qqmlconnections/data/rewriteError-unnamed.qml | 8 --- .../qqmlconnections/data/singletontype-target.qml | 22 ------- .../data/test-connection-implicit.qml | 9 --- .../qml/qqmlconnections/data/test-connection.qml | 10 --- tests/auto/qml/qqmlconnections/data/trimming.qml | 10 --- .../qml/qqmlconnections/tst_qqmlconnections.cpp | 70 ++++++++++++++++----- 46 files changed, 478 insertions(+), 176 deletions(-) create mode 100644 tests/auto/qml/qqmlconnections/data/bindings/connection-no-signal-name.qml create mode 100644 tests/auto/qml/qqmlconnections/data/bindings/connection-targetchange.qml create mode 100644 tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-ignored.qml create mode 100644 tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-notarget.qml create mode 100644 tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-parent.qml create mode 100644 tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals.qml create mode 100644 tests/auto/qml/qqmlconnections/data/bindings/disabled-at-start.qml create mode 100644 tests/auto/qml/qqmlconnections/data/bindings/override-proxy-type.qml create mode 100644 tests/auto/qml/qqmlconnections/data/bindings/rewriteError-global.qml create mode 100644 tests/auto/qml/qqmlconnections/data/bindings/rewriteError-unnamed.qml create mode 100644 tests/auto/qml/qqmlconnections/data/bindings/singletontype-target.qml create mode 100644 tests/auto/qml/qqmlconnections/data/bindings/test-connection-implicit.qml create mode 100644 tests/auto/qml/qqmlconnections/data/bindings/test-connection.qml create mode 100644 tests/auto/qml/qqmlconnections/data/bindings/trimming.qml delete mode 100644 tests/auto/qml/qqmlconnections/data/connection-no-signal-name.qml delete mode 100644 tests/auto/qml/qqmlconnections/data/connection-targetchange.qml delete mode 100644 tests/auto/qml/qqmlconnections/data/connection-unknownsignals-ignored.qml delete mode 100644 tests/auto/qml/qqmlconnections/data/connection-unknownsignals-notarget.qml delete mode 100644 tests/auto/qml/qqmlconnections/data/connection-unknownsignals-parent.qml delete mode 100644 tests/auto/qml/qqmlconnections/data/connection-unknownsignals.qml delete mode 100644 tests/auto/qml/qqmlconnections/data/disabled-at-start.qml create mode 100644 tests/auto/qml/qqmlconnections/data/functions/connection-no-signal-name.qml create mode 100644 tests/auto/qml/qqmlconnections/data/functions/connection-targetchange.qml create mode 100644 tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-ignored.qml create mode 100644 tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-notarget.qml create mode 100644 tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-parent.qml create mode 100644 tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals.qml create mode 100644 tests/auto/qml/qqmlconnections/data/functions/disabled-at-start.qml create mode 100644 tests/auto/qml/qqmlconnections/data/functions/override-proxy-type.qml create mode 100644 tests/auto/qml/qqmlconnections/data/functions/rewriteError-global.qml create mode 100644 tests/auto/qml/qqmlconnections/data/functions/rewriteError-unnamed.qml create mode 100644 tests/auto/qml/qqmlconnections/data/functions/singletontype-target.qml create mode 100644 tests/auto/qml/qqmlconnections/data/functions/test-connection-implicit.qml create mode 100644 tests/auto/qml/qqmlconnections/data/functions/test-connection.qml create mode 100644 tests/auto/qml/qqmlconnections/data/functions/trimming.qml delete mode 100644 tests/auto/qml/qqmlconnections/data/override-proxy-type.qml delete mode 100644 tests/auto/qml/qqmlconnections/data/rewriteError-global.qml delete mode 100644 tests/auto/qml/qqmlconnections/data/rewriteError-unnamed.qml delete mode 100644 tests/auto/qml/qqmlconnections/data/singletontype-target.qml delete mode 100644 tests/auto/qml/qqmlconnections/data/test-connection-implicit.qml delete mode 100644 tests/auto/qml/qqmlconnections/data/test-connection.qml delete mode 100644 tests/auto/qml/qqmlconnections/data/trimming.qml diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 20c8d53573..9c3c9de81e 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -206,8 +206,12 @@ void QQmlEnginePrivate::defineModule() qmlRegisterType(uri, 2, 0, "Binding"); qmlRegisterType(uri, 2, 8, "Binding"); // Only available in >= 2.8 qmlRegisterType(uri, 2, 14, "Binding"); + + // TODO: We won't need Connections to be a custom type anymore once we can drop the + // automatic signal handler inference from undeclared properties. qmlRegisterCustomType(uri, 2, 0, "Connections", new QQmlConnectionsParser); qmlRegisterCustomType(uri, 2, 3, "Connections", new QQmlConnectionsParser); // Only available in QtQml >= 2.3 + #if QT_CONFIG(qml_animation) qmlRegisterType(uri, 2, 0, "Timer"); #endif diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp index 8ec754a9df..14aadb6c86 100644 --- a/src/qml/types/qqmlconnections.cpp +++ b/src/qml/types/qqmlconnections.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -105,7 +106,7 @@ public: \qml MouseArea { Connections { - onClicked: foo(parameters) + function onClicked(mouse) { foo(mouse) } } } \endqml @@ -122,7 +123,7 @@ public: \qml Connections { target: area - onClicked: foo(parameters) + function onClicked(mouse) { foo(mouse) } } \endqml @@ -270,8 +271,73 @@ void QQmlConnections::connectSignals() if (!d->componentcomplete || (d->targetSet && !target())) return; - if (d->bindings.isEmpty()) + if (d->bindings.isEmpty()) { + connectSignalsToMethods(); + } else { + qmlWarning(this) << tr("Implicitly defined onFoo properties in Connections are deprecated. " + "Use this syntax instead: function onFoo() { ... }"); + connectSignalsToBindings(); + } +} + +void QQmlConnections::connectSignalsToMethods() +{ + Q_D(QQmlConnections); + + QObject *target = this->target(); + QQmlData *ddata = QQmlData::get(this); + if (!ddata) return; + + QV4::ExecutionEngine *engine = ddata->context->engine->handle(); + + QQmlContextData *ctxtdata = ddata->outerContext; + for (int i = ddata->propertyCache->methodOffset(), + end = ddata->propertyCache->methodOffset() + ddata->propertyCache->methodCount(); + i < end; + ++i) { + + QQmlPropertyData *handler = ddata->propertyCache->method(i); + if (!handler || !handler->isVMEFunction()) + continue; + + const QString propName = handler->name(this); + + QQmlProperty prop(target, propName); + if (prop.isValid() && (prop.type() & QQmlProperty::SignalProperty)) { + int signalIndex = QQmlPropertyPrivate::get(prop)->signalIndex(); + auto *signal = new QQmlBoundSignal(target, signalIndex, this, qmlEngine(this)); + signal->setEnabled(d->enabled); + + QV4::Scope scope(engine); + QV4::ScopedContext global(scope, engine->rootContext()); + + QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(this); + Q_ASSERT(vmeMetaObject); // the fact we found the property above should guarentee this + + QV4::ScopedFunctionObject method(scope, vmeMetaObject->vmeMethod(handler->coreIndex())); + + QQmlBoundSignalExpression *expression = + ctxtdata ? new QQmlBoundSignalExpression( + target, signalIndex, ctxtdata, this, + method->as()->function()) + : nullptr; + + signal->takeExpression(expression); + d->boundsignals += signal; + } else if (!d->ignoreUnknownSignals && propName.startsWith("on") && propName.length() > 2 + && propName.at(2).isUpper()) { + qmlWarning(this) << tr("Detected function \"%1\" in Connections element. " + "This is probably intended to be a signal handler but no " + "signal of the target matches the name.").arg(propName); + } + } +} + +// TODO: Drop this as soon as we can +void QQmlConnections::connectSignalsToBindings() +{ + Q_D(QQmlConnections); QObject *target = this->target(); QQmlData *ddata = QQmlData::get(this); QQmlContextData *ctxtdata = ddata ? ddata->outerContext : nullptr; diff --git a/src/qml/types/qqmlconnections_p.h b/src/qml/types/qqmlconnections_p.h index f6ad1eb46c..1acc86239f 100644 --- a/src/qml/types/qqmlconnections_p.h +++ b/src/qml/types/qqmlconnections_p.h @@ -91,10 +91,14 @@ Q_SIGNALS: private: void connectSignals(); + void connectSignalsToMethods(); + void connectSignalsToBindings(); + void classBegin() override; void componentComplete() override; }; +// TODO: Drop this class as soon as we can class QQmlConnectionsParser : public QQmlCustomParser { public: diff --git a/tests/auto/qml/qqmlconnections/data/bindings/connection-no-signal-name.qml b/tests/auto/qml/qqmlconnections/data/bindings/connection-no-signal-name.qml new file mode 100644 index 0000000000..462a9577ff --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/bindings/connection-no-signal-name.qml @@ -0,0 +1,15 @@ +import QtQuick 2.4 + +Item { + id: blaBlaBla + function hint() { + } + + Connections { + //target: blaBlaBla + //onHint: hint(); + on: true + } +} + + diff --git a/tests/auto/qml/qqmlconnections/data/bindings/connection-targetchange.qml b/tests/auto/qml/qqmlconnections/data/bindings/connection-targetchange.qml new file mode 100644 index 0000000000..154c309c9c --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/bindings/connection-targetchange.qml @@ -0,0 +1,25 @@ +import QtQuick 2.0 + +Item { + Component { + id: item1 + Item { + objectName: "item1" + } + } + Component { + id: item2 + Item { + objectName: "item2" + } + } + Loader { + id: loader + sourceComponent: item1 + } + Connections { + objectName: "connections" + target: loader.item + onWidthChanged: loader.sourceComponent = item2 + } +} diff --git a/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-ignored.qml b/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-ignored.qml new file mode 100644 index 0000000000..0780dd1509 --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-ignored.qml @@ -0,0 +1,8 @@ +import QtQml 2.0 + +QtObject { + id: root + + property Connections c1: Connections { target: root; onNotFooBar1: {} ignoreUnknownSignals: true } + property Connections c2: Connections { objectName: "connections"; onNotFooBar2: {} ignoreUnknownSignals: true } +} diff --git a/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-notarget.qml b/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-notarget.qml new file mode 100644 index 0000000000..3da3e0f5d1 --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-notarget.qml @@ -0,0 +1,5 @@ +import QtQml 2.0 + +QtObject { + property Connections c1: Connections { objectName: "connections"; target: null; onNotFooBar: {} } +} diff --git a/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-parent.qml b/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-parent.qml new file mode 100644 index 0000000000..2c55215579 --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-parent.qml @@ -0,0 +1,5 @@ +import QtQml 2.0 + +QtObject { + property Connections c1: Connections { objectName: "connections"; onFooBar: {} } +} diff --git a/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals.qml b/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals.qml new file mode 100644 index 0000000000..a351016b4a --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals.qml @@ -0,0 +1,7 @@ +import QtQml 2.0 + +QtObject { + id: screen + + property Connections c1: Connections { objectName: "connections"; target: screen; onFooBar: {} } +} diff --git a/tests/auto/qml/qqmlconnections/data/bindings/disabled-at-start.qml b/tests/auto/qml/qqmlconnections/data/bindings/disabled-at-start.qml new file mode 100644 index 0000000000..1a823f87f6 --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/bindings/disabled-at-start.qml @@ -0,0 +1,14 @@ +import QtQuick 2.9 + +Item { + id: root + + property bool tested: false + signal testMe() + + Connections { + target: root + enabled: false + onTestMe: root.tested = true; + } +} diff --git a/tests/auto/qml/qqmlconnections/data/bindings/override-proxy-type.qml b/tests/auto/qml/qqmlconnections/data/bindings/override-proxy-type.qml new file mode 100644 index 0000000000..80e459966b --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/bindings/override-proxy-type.qml @@ -0,0 +1,13 @@ +import QtQml 2.12 +import test.proxy 1.0 + +Proxy { + property int testEnum: 0; + id: proxy + property Connections connections: Connections { + target: proxy + onSomeSignal: testEnum = Proxy.EnumValue; + } + + Component.onCompleted: someSignal() +} diff --git a/tests/auto/qml/qqmlconnections/data/bindings/rewriteError-global.qml b/tests/auto/qml/qqmlconnections/data/bindings/rewriteError-global.qml new file mode 100644 index 0000000000..1d0b557069 --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/bindings/rewriteError-global.qml @@ -0,0 +1,8 @@ +import QtQml 2.0 +import Test 1.0 + +TestObject { + property QtObject connection: Connections { + onSignalWithGlobalName: { ran = true } + } +} diff --git a/tests/auto/qml/qqmlconnections/data/bindings/rewriteError-unnamed.qml b/tests/auto/qml/qqmlconnections/data/bindings/rewriteError-unnamed.qml new file mode 100644 index 0000000000..a4849e994b --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/bindings/rewriteError-unnamed.qml @@ -0,0 +1,8 @@ +import QtQuick 2.0 +import Test 1.0 + +TestObject { + property QtObject connection: Connections { + onUnnamedArgumentSignal: { ran = true } + } +} diff --git a/tests/auto/qml/qqmlconnections/data/bindings/singletontype-target.qml b/tests/auto/qml/qqmlconnections/data/bindings/singletontype-target.qml new file mode 100644 index 0000000000..7de488c2dd --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/bindings/singletontype-target.qml @@ -0,0 +1,22 @@ +import QtQml 2.0 +import MyTestSingletonType 1.0 as MyTestSingletonType + +QtObject { + id: rootObject + objectName: "rootObject" + property int newIntPropValue: 12 + + property int moduleIntPropChangedCount: 0 + property int moduleOtherSignalCount: 0 + + function setModuleIntProp() { + MyTestSingletonType.Api.intProp = newIntPropValue; + newIntPropValue = newIntPropValue + 1; + } + + property Connections c: Connections { + target: MyTestSingletonType.Api + onIntPropChanged: moduleIntPropChangedCount = moduleIntPropChangedCount + 1; + onOtherSignal: moduleOtherSignalCount = moduleOtherSignalCount + 1; + } +} diff --git a/tests/auto/qml/qqmlconnections/data/bindings/test-connection-implicit.qml b/tests/auto/qml/qqmlconnections/data/bindings/test-connection-implicit.qml new file mode 100644 index 0000000000..d5aa0f102a --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/bindings/test-connection-implicit.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 + +Item { + width: 50 + + property bool tested: false + + Connections { onWidthChanged: tested = true } +} diff --git a/tests/auto/qml/qqmlconnections/data/bindings/test-connection.qml b/tests/auto/qml/qqmlconnections/data/bindings/test-connection.qml new file mode 100644 index 0000000000..f44cbc047f --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/bindings/test-connection.qml @@ -0,0 +1,10 @@ +import QtQuick 2.0 + +Item { + id: screen; width: 50 + + property bool tested: false + signal testMe + + Connections { objectName: "connections"; target: screen; onWidthChanged: screen.tested = true } +} diff --git a/tests/auto/qml/qqmlconnections/data/bindings/trimming.qml b/tests/auto/qml/qqmlconnections/data/bindings/trimming.qml new file mode 100644 index 0000000000..4c37eb22af --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/bindings/trimming.qml @@ -0,0 +1,10 @@ +import QtQml 2.0 + +QtObject { + id: root + + property string tested + signal testMe(int param1, string param2) + + property Connections c: Connections { target: root; onTestMe: root.tested = param2 + param1 } +} diff --git a/tests/auto/qml/qqmlconnections/data/connection-no-signal-name.qml b/tests/auto/qml/qqmlconnections/data/connection-no-signal-name.qml deleted file mode 100644 index 462a9577ff..0000000000 --- a/tests/auto/qml/qqmlconnections/data/connection-no-signal-name.qml +++ /dev/null @@ -1,15 +0,0 @@ -import QtQuick 2.4 - -Item { - id: blaBlaBla - function hint() { - } - - Connections { - //target: blaBlaBla - //onHint: hint(); - on: true - } -} - - diff --git a/tests/auto/qml/qqmlconnections/data/connection-targetchange.qml b/tests/auto/qml/qqmlconnections/data/connection-targetchange.qml deleted file mode 100644 index 154c309c9c..0000000000 --- a/tests/auto/qml/qqmlconnections/data/connection-targetchange.qml +++ /dev/null @@ -1,25 +0,0 @@ -import QtQuick 2.0 - -Item { - Component { - id: item1 - Item { - objectName: "item1" - } - } - Component { - id: item2 - Item { - objectName: "item2" - } - } - Loader { - id: loader - sourceComponent: item1 - } - Connections { - objectName: "connections" - target: loader.item - onWidthChanged: loader.sourceComponent = item2 - } -} diff --git a/tests/auto/qml/qqmlconnections/data/connection-unknownsignals-ignored.qml b/tests/auto/qml/qqmlconnections/data/connection-unknownsignals-ignored.qml deleted file mode 100644 index 0780dd1509..0000000000 --- a/tests/auto/qml/qqmlconnections/data/connection-unknownsignals-ignored.qml +++ /dev/null @@ -1,8 +0,0 @@ -import QtQml 2.0 - -QtObject { - id: root - - property Connections c1: Connections { target: root; onNotFooBar1: {} ignoreUnknownSignals: true } - property Connections c2: Connections { objectName: "connections"; onNotFooBar2: {} ignoreUnknownSignals: true } -} diff --git a/tests/auto/qml/qqmlconnections/data/connection-unknownsignals-notarget.qml b/tests/auto/qml/qqmlconnections/data/connection-unknownsignals-notarget.qml deleted file mode 100644 index 3da3e0f5d1..0000000000 --- a/tests/auto/qml/qqmlconnections/data/connection-unknownsignals-notarget.qml +++ /dev/null @@ -1,5 +0,0 @@ -import QtQml 2.0 - -QtObject { - property Connections c1: Connections { objectName: "connections"; target: null; onNotFooBar: {} } -} diff --git a/tests/auto/qml/qqmlconnections/data/connection-unknownsignals-parent.qml b/tests/auto/qml/qqmlconnections/data/connection-unknownsignals-parent.qml deleted file mode 100644 index 2c55215579..0000000000 --- a/tests/auto/qml/qqmlconnections/data/connection-unknownsignals-parent.qml +++ /dev/null @@ -1,5 +0,0 @@ -import QtQml 2.0 - -QtObject { - property Connections c1: Connections { objectName: "connections"; onFooBar: {} } -} diff --git a/tests/auto/qml/qqmlconnections/data/connection-unknownsignals.qml b/tests/auto/qml/qqmlconnections/data/connection-unknownsignals.qml deleted file mode 100644 index a351016b4a..0000000000 --- a/tests/auto/qml/qqmlconnections/data/connection-unknownsignals.qml +++ /dev/null @@ -1,7 +0,0 @@ -import QtQml 2.0 - -QtObject { - id: screen - - property Connections c1: Connections { objectName: "connections"; target: screen; onFooBar: {} } -} diff --git a/tests/auto/qml/qqmlconnections/data/disabled-at-start.qml b/tests/auto/qml/qqmlconnections/data/disabled-at-start.qml deleted file mode 100644 index 1a823f87f6..0000000000 --- a/tests/auto/qml/qqmlconnections/data/disabled-at-start.qml +++ /dev/null @@ -1,14 +0,0 @@ -import QtQuick 2.9 - -Item { - id: root - - property bool tested: false - signal testMe() - - Connections { - target: root - enabled: false - onTestMe: root.tested = true; - } -} diff --git a/tests/auto/qml/qqmlconnections/data/functions/connection-no-signal-name.qml b/tests/auto/qml/qqmlconnections/data/functions/connection-no-signal-name.qml new file mode 100644 index 0000000000..04cc36b3c5 --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/functions/connection-no-signal-name.qml @@ -0,0 +1,15 @@ +import QtQuick 2.4 + +Item { + id: blaBlaBla + function hint() { + } + + Connections { + //target: blaBlaBla + // function onHint() { hint() }; + on: true + } +} + + diff --git a/tests/auto/qml/qqmlconnections/data/functions/connection-targetchange.qml b/tests/auto/qml/qqmlconnections/data/functions/connection-targetchange.qml new file mode 100644 index 0000000000..692194e837 --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/functions/connection-targetchange.qml @@ -0,0 +1,25 @@ +import QtQuick 2.0 + +Item { + Component { + id: item1 + Item { + objectName: "item1" + } + } + Component { + id: item2 + Item { + objectName: "item2" + } + } + Loader { + id: loader + sourceComponent: item1 + } + Connections { + objectName: "connections" + target: loader.item + function onWidthChanged() { loader.sourceComponent = item2 } + } +} diff --git a/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-ignored.qml b/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-ignored.qml new file mode 100644 index 0000000000..f70d8cdb15 --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-ignored.qml @@ -0,0 +1,17 @@ +import QtQml 2.0 + +QtObject { + id: root + + property Connections c1: Connections { + target: root; + function onNotFooBar1() {} + ignoreUnknownSignals: true + } + + property Connections c2: Connections { + objectName: "connections" + function onNotFooBar2() {} + ignoreUnknownSignals: true + } +} diff --git a/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-notarget.qml b/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-notarget.qml new file mode 100644 index 0000000000..7658728dd9 --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-notarget.qml @@ -0,0 +1,9 @@ +import QtQml 2.0 + +QtObject { + property Connections c1: Connections { + objectName: "connections" + target: null + function onNotFooBar() {} + } +} diff --git a/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-parent.qml b/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-parent.qml new file mode 100644 index 0000000000..ece76b0cf7 --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-parent.qml @@ -0,0 +1,8 @@ +import QtQml 2.0 + +QtObject { + property Connections c1: Connections { + objectName: "connections" + function onFooBar() {} + } +} diff --git a/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals.qml b/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals.qml new file mode 100644 index 0000000000..a198a724d0 --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals.qml @@ -0,0 +1,11 @@ +import QtQml 2.0 + +QtObject { + id: screen + + property Connections c1: Connections { + objectName: "connections" + target: screen + function onFooBar() {} + } +} diff --git a/tests/auto/qml/qqmlconnections/data/functions/disabled-at-start.qml b/tests/auto/qml/qqmlconnections/data/functions/disabled-at-start.qml new file mode 100644 index 0000000000..981437fe8c --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/functions/disabled-at-start.qml @@ -0,0 +1,14 @@ +import QtQuick 2.9 + +Item { + id: root + + property bool tested: false + signal testMe() + + Connections { + target: root + enabled: false + function onTestMe() { root.tested = true; } + } +} diff --git a/tests/auto/qml/qqmlconnections/data/functions/override-proxy-type.qml b/tests/auto/qml/qqmlconnections/data/functions/override-proxy-type.qml new file mode 100644 index 0000000000..b83f0baa11 --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/functions/override-proxy-type.qml @@ -0,0 +1,13 @@ +import QtQml 2.12 +import test.proxy 1.0 + +Proxy { + property int testEnum: 0; + id: proxy + property Connections connections: Connections { + target: proxy + function onSomeSignal() { testEnum = Proxy.EnumValue } + } + + Component.onCompleted: someSignal() +} diff --git a/tests/auto/qml/qqmlconnections/data/functions/rewriteError-global.qml b/tests/auto/qml/qqmlconnections/data/functions/rewriteError-global.qml new file mode 100644 index 0000000000..de3154c431 --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/functions/rewriteError-global.qml @@ -0,0 +1,8 @@ +import QtQml 2.0 +import Test 1.0 + +TestObject { + property QtObject connection: Connections { + function onSignalWithGlobalName() { ran = true } + } +} diff --git a/tests/auto/qml/qqmlconnections/data/functions/rewriteError-unnamed.qml b/tests/auto/qml/qqmlconnections/data/functions/rewriteError-unnamed.qml new file mode 100644 index 0000000000..fa1d1b17d7 --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/functions/rewriteError-unnamed.qml @@ -0,0 +1,8 @@ +import QtQuick 2.0 +import Test 1.0 + +TestObject { + property QtObject connection: Connections { + function onUnnamedArgumentSignal() { ran = true } + } +} diff --git a/tests/auto/qml/qqmlconnections/data/functions/singletontype-target.qml b/tests/auto/qml/qqmlconnections/data/functions/singletontype-target.qml new file mode 100644 index 0000000000..935b610351 --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/functions/singletontype-target.qml @@ -0,0 +1,22 @@ +import QtQml 2.0 +import MyTestSingletonType 1.0 as MyTestSingletonType + +QtObject { + id: rootObject + objectName: "rootObject" + property int newIntPropValue: 12 + + property int moduleIntPropChangedCount: 0 + property int moduleOtherSignalCount: 0 + + function setModuleIntProp() { + MyTestSingletonType.Api.intProp = newIntPropValue; + newIntPropValue = newIntPropValue + 1; + } + + property Connections c: Connections { + target: MyTestSingletonType.Api + function onIntPropChanged() { moduleIntPropChangedCount = moduleIntPropChangedCount + 1 } + function onOtherSignal() { moduleOtherSignalCount = moduleOtherSignalCount + 1 } + } +} diff --git a/tests/auto/qml/qqmlconnections/data/functions/test-connection-implicit.qml b/tests/auto/qml/qqmlconnections/data/functions/test-connection-implicit.qml new file mode 100644 index 0000000000..2ed5278636 --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/functions/test-connection-implicit.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 + +Item { + width: 50 + + property bool tested: false + + Connections { function onWidthChanged() { tested = true } } +} diff --git a/tests/auto/qml/qqmlconnections/data/functions/test-connection.qml b/tests/auto/qml/qqmlconnections/data/functions/test-connection.qml new file mode 100644 index 0000000000..c706797ea4 --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/functions/test-connection.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 + +Item { + id: screen; width: 50 + + property bool tested: false + signal testMe + + Connections { + objectName: "connections" + target: screen; + function onWidthChanged() { screen.tested = true } + } +} diff --git a/tests/auto/qml/qqmlconnections/data/functions/trimming.qml b/tests/auto/qml/qqmlconnections/data/functions/trimming.qml new file mode 100644 index 0000000000..7dfd673539 --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/functions/trimming.qml @@ -0,0 +1,13 @@ +import QtQml 2.0 + +QtObject { + id: root + + property string tested + signal testMe(int param1, string param2) + + property Connections c: Connections { + target: root + function onTestMe(param1, param2) { root.tested = param2 + param1 } + } +} diff --git a/tests/auto/qml/qqmlconnections/data/override-proxy-type.qml b/tests/auto/qml/qqmlconnections/data/override-proxy-type.qml deleted file mode 100644 index 80e459966b..0000000000 --- a/tests/auto/qml/qqmlconnections/data/override-proxy-type.qml +++ /dev/null @@ -1,13 +0,0 @@ -import QtQml 2.12 -import test.proxy 1.0 - -Proxy { - property int testEnum: 0; - id: proxy - property Connections connections: Connections { - target: proxy - onSomeSignal: testEnum = Proxy.EnumValue; - } - - Component.onCompleted: someSignal() -} diff --git a/tests/auto/qml/qqmlconnections/data/rewriteError-global.qml b/tests/auto/qml/qqmlconnections/data/rewriteError-global.qml deleted file mode 100644 index 1d0b557069..0000000000 --- a/tests/auto/qml/qqmlconnections/data/rewriteError-global.qml +++ /dev/null @@ -1,8 +0,0 @@ -import QtQml 2.0 -import Test 1.0 - -TestObject { - property QtObject connection: Connections { - onSignalWithGlobalName: { ran = true } - } -} diff --git a/tests/auto/qml/qqmlconnections/data/rewriteError-unnamed.qml b/tests/auto/qml/qqmlconnections/data/rewriteError-unnamed.qml deleted file mode 100644 index a4849e994b..0000000000 --- a/tests/auto/qml/qqmlconnections/data/rewriteError-unnamed.qml +++ /dev/null @@ -1,8 +0,0 @@ -import QtQuick 2.0 -import Test 1.0 - -TestObject { - property QtObject connection: Connections { - onUnnamedArgumentSignal: { ran = true } - } -} diff --git a/tests/auto/qml/qqmlconnections/data/singletontype-target.qml b/tests/auto/qml/qqmlconnections/data/singletontype-target.qml deleted file mode 100644 index 7de488c2dd..0000000000 --- a/tests/auto/qml/qqmlconnections/data/singletontype-target.qml +++ /dev/null @@ -1,22 +0,0 @@ -import QtQml 2.0 -import MyTestSingletonType 1.0 as MyTestSingletonType - -QtObject { - id: rootObject - objectName: "rootObject" - property int newIntPropValue: 12 - - property int moduleIntPropChangedCount: 0 - property int moduleOtherSignalCount: 0 - - function setModuleIntProp() { - MyTestSingletonType.Api.intProp = newIntPropValue; - newIntPropValue = newIntPropValue + 1; - } - - property Connections c: Connections { - target: MyTestSingletonType.Api - onIntPropChanged: moduleIntPropChangedCount = moduleIntPropChangedCount + 1; - onOtherSignal: moduleOtherSignalCount = moduleOtherSignalCount + 1; - } -} diff --git a/tests/auto/qml/qqmlconnections/data/test-connection-implicit.qml b/tests/auto/qml/qqmlconnections/data/test-connection-implicit.qml deleted file mode 100644 index d5aa0f102a..0000000000 --- a/tests/auto/qml/qqmlconnections/data/test-connection-implicit.qml +++ /dev/null @@ -1,9 +0,0 @@ -import QtQuick 2.0 - -Item { - width: 50 - - property bool tested: false - - Connections { onWidthChanged: tested = true } -} diff --git a/tests/auto/qml/qqmlconnections/data/test-connection.qml b/tests/auto/qml/qqmlconnections/data/test-connection.qml deleted file mode 100644 index f44cbc047f..0000000000 --- a/tests/auto/qml/qqmlconnections/data/test-connection.qml +++ /dev/null @@ -1,10 +0,0 @@ -import QtQuick 2.0 - -Item { - id: screen; width: 50 - - property bool tested: false - signal testMe - - Connections { objectName: "connections"; target: screen; onWidthChanged: screen.tested = true } -} diff --git a/tests/auto/qml/qqmlconnections/data/trimming.qml b/tests/auto/qml/qqmlconnections/data/trimming.qml deleted file mode 100644 index 4c37eb22af..0000000000 --- a/tests/auto/qml/qqmlconnections/data/trimming.qml +++ /dev/null @@ -1,10 +0,0 @@ -import QtQml 2.0 - -QtObject { - id: root - - property string tested - signal testMe(int param1, string param2) - - property Connections c: Connections { target: root; onTestMe: root.tested = param2 + param1 } -} diff --git a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp index 7e6a0f79f9..cf0f3c7bb3 100644 --- a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp +++ b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp @@ -42,29 +42,57 @@ public: private slots: void defaultValues(); void properties(); + + void connection_data() { prefixes(); } void connection(); + + void trimming_data() { prefixes(); } void trimming(); + + void targetChanged_data() { prefixes(); }; void targetChanged(); + void unknownSignals_data(); void unknownSignals(); + void errors_data(); void errors(); + + void rewriteErrors_data() { prefixes(); } void rewriteErrors(); + + void singletonTypeTarget_data() { prefixes(); } void singletonTypeTarget(); + + void enableDisable_QTBUG_36350_data() { prefixes(); } void enableDisable_QTBUG_36350(); + + void disabledAtStart_data() { prefixes(); } void disabledAtStart(); + + void clearImplicitTarget_data() { prefixes(); } void clearImplicitTarget(); void onWithoutASignal(); + + void noAcceleratedGlobalLookup_data() { prefixes(); } void noAcceleratedGlobalLookup(); private: QQmlEngine engine; + void prefixes(); }; tst_qqmlconnections::tst_qqmlconnections() { } +void tst_qqmlconnections::prefixes() +{ + QTest::addColumn("prefix"); + QTest::newRow("functions") << QString("functions"); + QTest::newRow("bindings") << QString("bindings"); +} + void tst_qqmlconnections::defaultValues() { QQmlEngine engine; @@ -93,8 +121,9 @@ void tst_qqmlconnections::properties() void tst_qqmlconnections::connection() { + QFETCH(QString, prefix); QQmlEngine engine; - QQmlComponent c(&engine, testFileUrl("test-connection.qml")); + QQmlComponent c(&engine, testFileUrl(prefix + "/test-connection.qml")); QQuickItem *item = qobject_cast(c.create()); QVERIFY(item != nullptr); @@ -110,8 +139,9 @@ void tst_qqmlconnections::connection() void tst_qqmlconnections::trimming() { + QFETCH(QString, prefix); QQmlEngine engine; - QQmlComponent c(&engine, testFileUrl("trimming.qml")); + QQmlComponent c(&engine, testFileUrl(prefix + "/trimming.qml")); QObject *object = c.create(); QVERIFY(object != nullptr); @@ -131,8 +161,9 @@ void tst_qqmlconnections::trimming() // Confirm that target can be changed by one of our signal handlers void tst_qqmlconnections::targetChanged() { + QFETCH(QString, prefix); QQmlEngine engine; - QQmlComponent c(&engine, testFileUrl("connection-targetchange.qml")); + QQmlComponent c(&engine, testFileUrl(prefix + "/connection-targetchange.qml")); QQuickItem *item = qobject_cast(c.create()); QVERIFY(item != nullptr); @@ -158,10 +189,15 @@ void tst_qqmlconnections::unknownSignals_data() QTest::addColumn("file"); QTest::addColumn("error"); - QTest::newRow("basic") << "connection-unknownsignals.qml" << ":6:30: QML Connections: Cannot assign to non-existent property \"onFooBar\""; - QTest::newRow("parent") << "connection-unknownsignals-parent.qml" << ":4:30: QML Connections: Cannot assign to non-existent property \"onFooBar\""; - QTest::newRow("ignored") << "connection-unknownsignals-ignored.qml" << ""; // should be NO error - QTest::newRow("notarget") << "connection-unknownsignals-notarget.qml" << ""; // should be NO error + QTest::newRow("functions/basic") << "functions/connection-unknownsignals.qml" << ":6:30: QML Connections: Detected function \"onFooBar\" in Connections element. This is probably intended to be a signal handler but no signal of the target matches the name."; + QTest::newRow("functions/parent") << "functions/connection-unknownsignals-parent.qml" << ":4:30: QML Connections: Detected function \"onFooBar\" in Connections element. This is probably intended to be a signal handler but no signal of the target matches the name."; + QTest::newRow("functions/ignored") << "functions/connection-unknownsignals-ignored.qml" << ""; // should be NO error + QTest::newRow("functions/notarget") << "functions/connection-unknownsignals-notarget.qml" << ""; // should be NO error + + QTest::newRow("bindings/basic") << "bindings/connection-unknownsignals.qml" << ":6:30: QML Connections: Cannot assign to non-existent property \"onFooBar\""; + QTest::newRow("bindings/parent") << "bindings/connection-unknownsignals-parent.qml" << ":4:30: QML Connections: Cannot assign to non-existent property \"onFooBar\""; + QTest::newRow("bindings/ignored") << "bindings/connection-unknownsignals-ignored.qml" << ""; // should be NO error + QTest::newRow("bindings/notarget") << "bindings/connection-unknownsignals-notarget.qml" << ""; // should be NO error } void tst_qqmlconnections::unknownSignals() @@ -239,10 +275,11 @@ private: void tst_qqmlconnections::rewriteErrors() { + QFETCH(QString, prefix); qmlRegisterType("Test", 1, 0, "TestObject"); { QQmlEngine engine; - QQmlComponent c(&engine, testFileUrl("rewriteError-unnamed.qml")); + QQmlComponent c(&engine, testFileUrl(prefix + "/rewriteError-unnamed.qml")); QTest::ignoreMessage(QtWarningMsg, (c.url().toString() + ":5:35: QML Connections: Signal uses unnamed parameter followed by named parameter.").toLatin1()); TestObject *obj = qobject_cast(c.create()); QVERIFY(obj != nullptr); @@ -254,7 +291,7 @@ void tst_qqmlconnections::rewriteErrors() { QQmlEngine engine; - QQmlComponent c(&engine, testFileUrl("rewriteError-global.qml")); + QQmlComponent c(&engine, testFileUrl(prefix + "/rewriteError-global.qml")); QTest::ignoreMessage(QtWarningMsg, (c.url().toString() + ":5:35: QML Connections: Signal parameter \"parseInt\" hides global variable.").toLatin1()); TestObject *obj = qobject_cast(c.create()); QVERIFY(obj != nullptr); @@ -305,8 +342,9 @@ static QObject *module_api_factory(QQmlEngine *engine, QJSEngine *scriptEngine) // QTBUG-20937 void tst_qqmlconnections::singletonTypeTarget() { + QFETCH(QString, prefix); qmlRegisterSingletonType("MyTestSingletonType", 1, 0, "Api", module_api_factory); - QQmlComponent component(&engine, testFileUrl("singletontype-target.qml")); + QQmlComponent component(&engine, testFileUrl(prefix + "/singletontype-target.qml")); QObject *object = component.create(); QVERIFY(object != nullptr); @@ -331,8 +369,9 @@ void tst_qqmlconnections::singletonTypeTarget() void tst_qqmlconnections::enableDisable_QTBUG_36350() { + QFETCH(QString, prefix); QQmlEngine engine; - QQmlComponent c(&engine, testFileUrl("test-connection.qml")); + QQmlComponent c(&engine, testFileUrl(prefix + "/test-connection.qml")); QQuickItem *item = qobject_cast(c.create()); QVERIFY(item != nullptr); @@ -358,8 +397,9 @@ void tst_qqmlconnections::enableDisable_QTBUG_36350() void tst_qqmlconnections::disabledAtStart() { + QFETCH(QString, prefix); QQmlEngine engine; - QQmlComponent c(&engine, testFileUrl("disabled-at-start.qml")); + QQmlComponent c(&engine, testFileUrl(prefix + "/disabled-at-start.qml")); QObject * const object = c.create(); QVERIFY(object != nullptr); @@ -376,8 +416,9 @@ void tst_qqmlconnections::disabledAtStart() //QTBUG-56499 void tst_qqmlconnections::clearImplicitTarget() { + QFETCH(QString, prefix); QQmlEngine engine; - QQmlComponent c(&engine, testFileUrl("test-connection-implicit.qml")); + QQmlComponent c(&engine, testFileUrl(prefix + "/test-connection-implicit.qml")); QQuickItem *item = qobject_cast(c.create()); QVERIFY(item != nullptr); @@ -421,10 +462,11 @@ signals: void tst_qqmlconnections::noAcceleratedGlobalLookup() { + QFETCH(QString, prefix); qRegisterMetaType(); qmlRegisterType("test.proxy", 1, 0, "Proxy"); QQmlEngine engine; - QQmlComponent c(&engine, testFileUrl("override-proxy-type.qml")); + QQmlComponent c(&engine, testFileUrl(prefix + "/override-proxy-type.qml")); QVERIFY(c.isReady()); QScopedPointer object(c.create()); const QVariant val = object->property("testEnum"); -- cgit v1.2.3 From 412be2096cea12ca480cbbd419f3531a41dac3ae Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 15 Aug 2019 21:43:16 +0200 Subject: QSGDepthStencilBufferManager: don't use toStrongRef().data() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's an anti-pattern. Even though we don't expect other threads to destroy the last QSP while we use the pointer obtained from QWeakPointer, play it safe and use QWeakPointer idiomatically: as a non-owning reference, to be converted to an owning one for the duration of our use of the payload object. Add an assertion that explains why we don't expect expired weak_ptrs here. Amends 0f035c0ad79ca41a1473b64a4c0077e7085d3700. Change-Id: Ia39ef5fa243e0e73110aae13da35f4f2ada73a73 Reviewed-by: Volker Hilsheimer Reviewed-by: Friedemann Kleint Reviewed-by: Mårten Nordheim --- src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp b/src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp index a850f72053..1154c06d7c 100644 --- a/src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp +++ b/src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp @@ -183,7 +183,9 @@ void QSGDefaultDepthStencilBuffer::free() QSGDepthStencilBufferManager::~QSGDepthStencilBufferManager() { for (Hash::const_iterator it = m_buffers.constBegin(), cend = m_buffers.constEnd(); it != cend; ++it) { - QSGDepthStencilBuffer *buffer = it.value().toStrongRef().data(); + QSharedPointer buffer = it.value().toStrongRef(); + Q_ASSERT_X(buffer, "~QSGDepthStencilBufferManager", + "~QSGDepthStencilBuffer is supposed to unregister from the manager"); buffer->free(); buffer->m_manager = nullptr; } -- cgit v1.2.3 From 527687a866d1a155314c1b6d4b8a09533cf8211a Mon Sep 17 00:00:00 2001 From: Alexandru Croitor Date: Tue, 16 Jul 2019 15:07:51 +0200 Subject: CMake: Provide API to allow handling of QML static plugins This change adds a new -cmake-output command line argument to qmlimportscanner which outputs its result in a format which is consumable by CMake. This change also adds a new CMake package called Qt5QmlImportScanner. It provides a function called QT5_IMPORT_QML_PLUGINS() which is useful for projects that use a static build of Qt and which also use QML plugins. Calling it with the target name of your application does the following: - Runs qmlimportscanner at configure time to find out which QML / QtQuick plugins are used by your project - Links the imported QML plugins into the target - Links the static dependencies of the QML plugins into the target - Generates a .cpp file that initializes imported QML plugins, which is subsequently compiled and linked into the given target When Qt is built in a shared library config, the introduced function is a no-op. [ChangeLog][CMake] Added ability to import static qml plugins with CMake builds using the new QT5_IMPORT_QML_PLUGINS function. Task-number: QTBUG-38913 Change-Id: Ib9b9a69654eab13dfbe12d10f5cb28ba3c307d1b Reviewed-by: Ulf Hermann --- tests/auto/cmake/CMakeLists.txt | 12 ++ tests/auto/cmake/qmlimportscanner/CMakeLists.txt | 18 ++ tests/auto/cmake/qmlimportscanner/main.cpp | 53 ++++++ tests/auto/cmake/qmlimportscanner/main.qml | 5 + tests/auto/cmake/qmlimportscanner/qis_test.qrc | 6 + .../Qt5QmlImportScannerConfig.cmake.in | 184 +++++++++++++++++++++ .../Qt5QmlImportScannerTemplate.cpp.in | 5 + tools/qmlimportscanner/main.cpp | 46 +++++- tools/qmlimportscanner/qmlimportscanner.pro | 45 +++++ 9 files changed, 371 insertions(+), 3 deletions(-) create mode 100644 tests/auto/cmake/qmlimportscanner/CMakeLists.txt create mode 100644 tests/auto/cmake/qmlimportscanner/main.cpp create mode 100644 tests/auto/cmake/qmlimportscanner/main.qml create mode 100644 tests/auto/cmake/qmlimportscanner/qis_test.qrc create mode 100644 tools/qmlimportscanner/Qt5QmlImportScannerConfig.cmake.in create mode 100644 tools/qmlimportscanner/Qt5QmlImportScannerTemplate.cpp.in diff --git a/tests/auto/cmake/CMakeLists.txt b/tests/auto/cmake/CMakeLists.txt index f304a99705..bda5d626a9 100644 --- a/tests/auto/cmake/CMakeLists.txt +++ b/tests/auto/cmake/CMakeLists.txt @@ -27,3 +27,15 @@ add_test(qtquickcompiler ${CMAKE_CTEST_COMMAND} --build-options "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}" ${BUILD_OPTIONS_LIST} --test-command qqc_test ) + +add_test(qmlimportscanner ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMAKE_CURRENT_SOURCE_DIR}/qmlimportscanner/" + "${CMAKE_CURRENT_BINARY_DIR}/qmlimportscanner" + --build-config "${CMAKE_BUILD_TYPE}" + --build-generator ${CMAKE_GENERATOR} + --build-makeprogram ${CMAKE_MAKE_PROGRAM} + --build-project qis_test + --build-options "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}" ${BUILD_OPTIONS_LIST} + --test-command qis_test +) diff --git a/tests/auto/cmake/qmlimportscanner/CMakeLists.txt b/tests/auto/cmake/qmlimportscanner/CMakeLists.txt new file mode 100644 index 0000000000..354b0f8dfc --- /dev/null +++ b/tests/auto/cmake/qmlimportscanner/CMakeLists.txt @@ -0,0 +1,18 @@ + +cmake_minimum_required(VERSION 3.1) +project(qis_test) + +find_package(Qt5Qml 5.0.0 REQUIRED) +find_package(Qt5Gui 5.0.0 REQUIRED) +find_package(Qt5Test 5.0.0 REQUIRED) +find_package(Qt5QmlImportScanner REQUIRED) + +set(CMAKE_CXXFLAGS "${CMAKE_CXXFLAGS} ${Qt5Core_EXECUTABLE_COMPILE_FLAGS}") + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +add_executable(qis_test "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/qis_test.qrc") +target_link_libraries(qis_test PRIVATE Qt5::Gui Qt5::Qml Qt5::Test) +qt5_import_qml_plugins(qis_test) diff --git a/tests/auto/cmake/qmlimportscanner/main.cpp b/tests/auto/cmake/qmlimportscanner/main.cpp new file mode 100644 index 0000000000..370b10e113 --- /dev/null +++ b/tests/auto/cmake/qmlimportscanner/main.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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 +#include +#include + +class tst_QQC : public QObject +{ + Q_OBJECT +private slots: + void staticBuildTest(); +}; + +void tst_QQC::staticBuildTest() +{ +#ifdef QT_STATIC + QQmlEngine engine; + QQmlComponent component(&engine, QUrl("qrc:/main.qml")); + QScopedPointer obj(component.create()); + QVERIFY(!obj.isNull()); + QCOMPARE(obj->property("success").toInt(), 42); +#endif +} + +QTEST_MAIN(tst_QQC) + +#include "main.moc" diff --git a/tests/auto/cmake/qmlimportscanner/main.qml b/tests/auto/cmake/qmlimportscanner/main.qml new file mode 100644 index 0000000000..e0101958ea --- /dev/null +++ b/tests/auto/cmake/qmlimportscanner/main.qml @@ -0,0 +1,5 @@ +import QtQml 2.0 +import QtQuick 2.0 +QtObject { + property int success: 42 +} diff --git a/tests/auto/cmake/qmlimportscanner/qis_test.qrc b/tests/auto/cmake/qmlimportscanner/qis_test.qrc new file mode 100644 index 0000000000..1f88fc4e71 --- /dev/null +++ b/tests/auto/cmake/qmlimportscanner/qis_test.qrc @@ -0,0 +1,6 @@ + + +./main.qml +./main.cpp + + diff --git a/tools/qmlimportscanner/Qt5QmlImportScannerConfig.cmake.in b/tools/qmlimportscanner/Qt5QmlImportScannerConfig.cmake.in new file mode 100644 index 0000000000..6cdfaf8f6f --- /dev/null +++ b/tools/qmlimportscanner/Qt5QmlImportScannerConfig.cmake.in @@ -0,0 +1,184 @@ +include(CMakeParseArguments) + +function(QT5_IMPORT_QML_PLUGINS target) +!!IF !isEmpty(CMAKE_STATIC_TYPE) + set(options) + set(oneValueArgs \"PATH_TO_SCAN\") + set(multiValueArgs) + + cmake_parse_arguments(arg \"${options}\" \"${oneValueArgs}\" \"${multiValueArgs}\" ${ARGN}) + if(NOT arg_PATH_TO_SCAN) + set(arg_PATH_TO_SCAN \"${CMAKE_CURRENT_SOURCE_DIR}\") + endif() + + # Find location of qmlimportscanner. + find_package(Qt5 COMPONENTS Core) +!!IF isEmpty(CMAKE_BIN_DIR_IS_ABSOLUTE) + set(tool_path + \"${_qt5Core_install_prefix}/$${CMAKE_BIN_DIR}qmlimportscanner$$CMAKE_BIN_SUFFIX\") +!!ELSE + set(tool_path \"$${CMAKE_BIN_DIR}qmlimportscanner$$CMAKE_BIN_SUFFIX\") +!!ENDIF + if(NOT EXISTS \"${tool_path}\" ) + message(FATAL_ERROR \"The package \\\"Qt5QmlImportScannerConfig\\\" references the file + \\\"${tool_path}\\\" +but this file does not exist. Possible reasons include: +* The file was deleted, renamed, or moved to another location. +* An install or uninstall procedure did not complete successfully. +* The installation package was faulty. +\") + endif() + + # Find location of qml dir. +!!IF isEmpty(CMAKE_QML_DIR_IS_ABSOLUTE) + set(qml_path \"${_qt5Core_install_prefix}/$${CMAKE_QML_DIR}\") +!!ELSE + set(qml_path \"$${CMAKE_QML_DIR}\") +!!ENDIF + + # Small macro to avoid duplicating code in two different loops. + macro(_qt5_QmlImportScanner_parse_entry) + set(entry_name \"qml_import_scanner_import_${idx}\") + cmake_parse_arguments(\"entry\" + \"\" + \"CLASSNAME;NAME;PATH;PLUGIN;RELATIVEPATH;TYPE;VERSION;\" \"\" + ${${entry_name}}) + endmacro() + + # Macro used to populate the dependency link flags for a certain configuriation (debug vs + # release) of a plugin. + macro(_qt5_link_to_QmlImportScanner_library_dependencies Plugin Configuration PluginLocation + IsDebugAndRelease) + + set_property(TARGET \"${Plugin}\" APPEND PROPERTY IMPORTED_CONFIGURATIONS ${Configuration}) + set(_imported_location \"${PluginLocation}\") + _qt5_Core_check_file_exists(\"${_imported_location}\") + set_target_properties(\"${Plugin}\" PROPERTIES + \"IMPORTED_LOCATION_${Configuration}\" \"${_imported_location}\" + ) + + set(_static_deps + ${_Qt5${entry_PLUGIN}_STATIC_${Configuration}_LIB_DEPENDENCIES} + ) + + if(NOT "${IsDebugAndRelease}") + set(_genex_condition \"1\") + else() + if("${Configuration}" STREQUAL "DEBUG") + set(_genex_condition \"$\") + else() + set(_genex_condition \"$>\") + endif() + endif() + if(_static_deps) + set(_static_deps_genex \"$<${_genex_condition}:${_static_deps}>\") + target_link_libraries(${imported_target} INTERFACE \"${_static_deps_genex}\") + endif() + + set(_static_link_flags \"${_Qt5${entry_PLUGIN}_STATIC_${Configuration}_LINK_FLAGS}\") + if(NOT CMAKE_VERSION VERSION_LESS \"3.13\" AND _static_link_flags) + set(_static_link_flags_genex \"$<${_genex_condition}:${_static_link_flags}>\") + target_link_options(${imported_target} INTERFACE \"${_static_link_flags_genex}\") + endif() + endmacro() + + # Run qmlimportscanner and include the generated cmake file. + set(qml_imports_file_path + \"${CMAKE_CURRENT_BINARY_DIR}/Qt5_QmlPlugins_Imports_${target}.cmake\") + + message(STATUS \"Running qmlimportscanner to find used QML plugins. \") + execute_process(COMMAND + \"${tool_path}\" \"${arg_PATH_TO_SCAN}\" -importPath \"${qml_path}\" + -cmake-output + OUTPUT_FILE \"${qml_imports_file_path}\") + + include(\"${qml_imports_file_path}\" OPTIONAL RESULT_VARIABLE qml_imports_file_path_found) + if(NOT qml_imports_file_path_found) + message(FATAL_ERROR \"Could not find ${qml_imports_file_path} which was supposed to be generated by qmlimportscanner.\") + endif() + + # Parse the generate cmake file. + # It is possible for the scanner to find no usage of QML, in which case the import count is 0. + if(qml_import_scanner_imports_count) + set(added_plugins \"\") + foreach(idx RANGE \"${qml_import_scanner_imports_count}\") + _qt5_QmlImportScanner_parse_entry() + if(entry_PATH AND entry_PLUGIN) + # Sometimes a plugin appears multiple times with different versions. + # Make sure to process it only once. + list(FIND added_plugins \"${entry_PLUGIN}\" _index) + if(NOT _index EQUAL -1) + continue() + endif() + list(APPEND added_plugins \"${entry_PLUGIN}\") + + # Add an imported target that will contain the link libraries and link options read + # from one plugin prl file. This target will point to the actual plugin and contain + # static dependency libraries and link flags. + # By creating a target for each qml plugin, CMake will take care of link flag + # deduplication. + set(imported_target \"${target}_QmlImport_${entry_PLUGIN}\") + add_library(\"${imported_target}\" MODULE IMPORTED) + target_link_libraries(\"${target}\" PRIVATE \"${imported_target}\") + + # Read static library dependencies from the plugin .prl file. + # And then set the link flags to the library dependencies extracted from the .prl + # file. +!!IF !isEmpty(CMAKE_RELEASE_TYPE) + _qt5_Core_process_prl_file( + \"${entry_PATH}/$$QMAKE_PREFIX_STATICLIB${entry_PLUGIN}$${CMAKE_QML_PLUGIN_SUFFIX_RELEASE}.prl\" RELEASE + _Qt5${entry_PLUGIN}_STATIC_RELEASE_LIB_DEPENDENCIES + _Qt5${entry_PLUGIN}_STATIC_RELEASE_LINK_FLAGS + ) + _qt5_link_to_QmlImportScanner_library_dependencies( + \"${imported_target}\" + RELEASE + \"${entry_PATH}/$$QMAKE_PREFIX_STATICLIB${entry_PLUGIN}$${CMAKE_QML_PLUGIN_SUFFIX_RELEASE}.$$QMAKE_EXTENSION_STATICLIB\" + $${CMAKE_DEBUG_AND_RELEASE}) +!!ENDIF + +!!IF !isEmpty(CMAKE_DEBUG_TYPE) + _qt5_Core_process_prl_file( + \"${entry_PATH}/$$QMAKE_PREFIX_STATICLIB${entry_PLUGIN}$${CMAKE_QML_PLUGIN_SUFFIX_DEBUG}.prl\" DEBUG + _Qt5${entry_PLUGIN}_STATIC_DEBUG_LIB_DEPENDENCIES + _Qt5${entry_PLUGIN}_STATIC_DEBUG_LINK_FLAGS + ) + _qt5_link_to_QmlImportScanner_library_dependencies( + \"${imported_target}\" + DEBUG + \"${entry_PATH}/$$QMAKE_PREFIX_STATICLIB${entry_PLUGIN}$${CMAKE_QML_PLUGIN_SUFFIX_DEBUG}.$$QMAKE_EXTENSION_STATICLIB\" + $${CMAKE_DEBUG_AND_RELEASE}) +!!ENDIF + endif() + endforeach() + + # Generate content for plugin initialization cpp file. + set(added_imports \"\") + set(qt5_qml_import_cpp_file_content \"\") + foreach(idx RANGE \"${qml_import_scanner_imports_count}\") + _qt5_QmlImportScanner_parse_entry() + if(entry_PLUGIN) + if(entry_CLASSNAME) + list(FIND added_imports \"${entry_PLUGIN}\" _index) + if(_index EQUAL -1) + string(APPEND qt5_qml_import_cpp_file_content + \"Q_IMPORT_PLUGIN(${entry_CLASSNAME})\n\") + list(APPEND added_imports \"${entry_PLUGIN}\") + endif() + else() + message(FATAL_ERROR + \"Plugin ${entry_PLUGIN} is missing a classname entry, please add one to the qmldir file.\") + endif() + endif() + endforeach() + + # Write to the generated file, and include it as a source for the given target. + set(generated_import_cpp_path + \"${CMAKE_CURRENT_BINARY_DIR}/Qt5_QmlPlugins_Imports_${target}.cpp\") + configure_file(\"${Qt5QmlImportScanner_DIR}/Qt5QmlImportScannerTemplate.cpp.in\" + \"${generated_import_cpp_path}\" + @ONLY) + target_sources(${target} PRIVATE \"${generated_import_cpp_path}\") + endif() +!!ENDIF // !isEmpty(CMAKE_STATIC_TYPE) +endfunction() diff --git a/tools/qmlimportscanner/Qt5QmlImportScannerTemplate.cpp.in b/tools/qmlimportscanner/Qt5QmlImportScannerTemplate.cpp.in new file mode 100644 index 0000000000..4ed747a555 --- /dev/null +++ b/tools/qmlimportscanner/Qt5QmlImportScannerTemplate.cpp.in @@ -0,0 +1,5 @@ +// This file is autogenerated by CMake. It imports static plugin classes for +// static plugins used by QML imports. +#include + +@qt5_qml_import_cpp_file_content@ diff --git a/tools/qmlimportscanner/main.cpp b/tools/qmlimportscanner/main.cpp index 05d1f7fdc0..6d48f6203d 100644 --- a/tools/qmlimportscanner/main.cpp +++ b/tools/qmlimportscanner/main.cpp @@ -496,6 +496,36 @@ QVariantList findQmlImportsRecursively(const QStringList &qmlDirs, const QString return ret; } + +QString generateCmakeIncludeFileContent(const QVariantList &importList) { + // The function assumes that "list" is a QVariantList with 0 or more QVariantMaps, where + // each map contains QString -> QVariant mappings. This matches with the structure + // that qmake parses for static qml plugin auto imporitng. + // So: [ {"a": "a","b": "b"}, {"c": "c"} ] + QString content; + QTextStream s(&content); + int importsCount = 0; + for (const QVariant &importVariant: importList) { + if (static_cast(importVariant.type()) == QMetaType::QVariantMap) { + s << QStringLiteral("set(qml_import_scanner_import_") << importsCount + << QStringLiteral(" \""); + + const QMap &importDict = importVariant.toMap(); + for (auto it = importDict.cbegin(); it != importDict.cend(); ++it) { + s << it.key().toUpper() << QLatin1Char(';') + << it.value().toString() << QLatin1Char(';'); + } + s << QStringLiteral("\")\n"); + ++importsCount; + } + } + if (importsCount >= 0) { + content.prepend(QString(QStringLiteral("set(qml_import_scanner_imports_count %1)\n")) + .arg(importsCount)); + } + return content; +} + } // namespace int main(int argc, char *argv[]) @@ -512,6 +542,7 @@ int main(int argc, char *argv[]) QStringList qmlRootPaths; QStringList scanFiles; QStringList qmlImportPaths; + bool generateCmakeContent = false; int i = 1; while (i < args.count()) { @@ -536,6 +567,8 @@ int main(int argc, char *argv[]) if (i >= args.count()) std::cerr << "-importPath requires an argument\n"; argReceiver = &qmlImportPaths; + } else if (arg == QLatin1String("-cmake-output")) { + generateCmakeContent = true; } else { std::cerr << qPrintable(appName) << ": Invalid argument: \"" << qPrintable(arg) << "\"\n"; @@ -562,8 +595,15 @@ int main(int argc, char *argv[]) // Find the imports! QVariantList imports = findQmlImportsRecursively(qmlRootPaths, scanFiles); - // Convert to JSON - QByteArray json = QJsonDocument(QJsonArray::fromVariantList(imports)).toJson(); - std::cout << json.constData() << std::endl; + QByteArray content; + if (generateCmakeContent) { + // Convert to CMake code + content = generateCmakeIncludeFileContent(imports).toUtf8(); + } else { + // Convert to JSON + content = QJsonDocument(QJsonArray::fromVariantList(imports)).toJson(); + } + + std::cout << content.constData() << std::endl; return 0; } diff --git a/tools/qmlimportscanner/qmlimportscanner.pro b/tools/qmlimportscanner/qmlimportscanner.pro index 0b3a03abf3..a29b582274 100644 --- a/tools/qmlimportscanner/qmlimportscanner.pro +++ b/tools/qmlimportscanner/qmlimportscanner.pro @@ -5,6 +5,51 @@ DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII SOURCES += main.cpp +load(cmake_functions) + +CMAKE_BIN_DIR = $$cmakeRelativePath($$[QT_HOST_BINS], $$[QT_INSTALL_PREFIX]) +contains(CMAKE_BIN_DIR, "^\\.\\./.*") { + CMAKE_BIN_DIR = $$[QT_HOST_BINS]/ + CMAKE_BIN_DIR_IS_ABSOLUTE = True +} + +CMAKE_QML_DIR = $$cmakeRelativePath($$[QT_INSTALL_QML/get], $$[QT_INSTALL_PREFIX]) +contains(CMAKE_QML_DIR, "^\\.\\./.*") { + CMAKE_QML_DIR = $$[QT_INSTALL_QML/get]/ + CMAKE_QML_DIR_IS_ABSOLUTE = True +} +load(qt_build_paths) + +static|staticlib:CMAKE_STATIC_TYPE = true + +# Compute the platform target suffix. +CMAKE_QML_PLUGIN_SUFFIX_RELEASE = +win32: CMAKE_QML_PLUGIN_SUFFIX_DEBUG = d +else:darwin: CMAKE_QML_PLUGIN_SUFFIX_DEBUG = _debug +else: CMAKE_QML_PLUGIN_SUFFIX_DEBUG = + +# Find out which configurations should be handled in the generated Config.cmake file. +CMAKE_DEBUG_TYPE = +CMAKE_RELEASE_TYPE = +if(qtConfig(debug_and_release)|contains(QT_CONFIG, debug, debug|release)): CMAKE_DEBUG_TYPE = debug +if(qtConfig(debug_and_release)|contains(QT_CONFIG, release, debug|release)): CMAKE_RELEASE_TYPE = release + +qtConfig(debug_and_release) { + CMAKE_DEBUG_AND_RELEASE = TRUE +} else { + CMAKE_DEBUG_AND_RELEASE = FALSE +} + +equals(QMAKE_HOST.os, Windows): CMAKE_BIN_SUFFIX = ".exe" +cmake_config_file.input = $$PWD/Qt5QmlImportScannerConfig.cmake.in +cmake_config_file.output = $$MODULE_BASE_OUTDIR/lib/cmake/Qt5QmlImportScanner/Qt5QmlImportScannerConfig.cmake +QMAKE_SUBSTITUTES += cmake_config_file + +cmake_build_integration.files = $$cmake_config_file.output $$PWD/Qt5QmlImportScannerTemplate.cpp.in +cmake_build_integration.path = $$[QT_INSTALL_LIBS]/cmake/Qt5QmlImportScanner +prefix_build: INSTALLS += cmake_build_integration +else: COPIES += cmake_build_integration + QMAKE_TARGET_DESCRIPTION = QML Import Scanner load(qt_tool) -- cgit v1.2.3 From 46ed97609721318a5ac443e8ff5b17bd359ef305 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Wed, 7 Aug 2019 11:34:56 +0200 Subject: Rescale on rhi path too when NPoT textures not supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QRhi will not do this for us. Also handle mipmap filtering correctly in this regard. This will fix rendering on WebAssembly. Change-Id: I93a77b7c42bb43c59dfb7748f9fdbd7aa55f39bb Reviewed-by: Christian Strømme --- src/quick/scenegraph/util/qsgplaintexture.cpp | 13 +++++++++++++ src/quick/scenegraph/util/qsgtexturematerial.cpp | 1 + 2 files changed, 14 insertions(+) diff --git a/src/quick/scenegraph/util/qsgplaintexture.cpp b/src/quick/scenegraph/util/qsgplaintexture.cpp index 4c2b452b45..72313db836 100644 --- a/src/quick/scenegraph/util/qsgplaintexture.cpp +++ b/src/quick/scenegraph/util/qsgplaintexture.cpp @@ -378,6 +378,19 @@ void QSGPlainTexturePrivate::updateRhiTexture(QRhi *rhi, QRhiResourceUpdateBatch q->m_texture_size = tmp.size(); } + if ((q->mipmapFiltering() != QSGTexture::None + || q->horizontalWrapMode() != QSGTexture::ClampToEdge + || q->verticalWrapMode() != QSGTexture::ClampToEdge) + && !rhi->isFeatureSupported(QRhi::NPOTTextureRepeat)) + { + const int w = qNextPowerOfTwo(tmp.width() - 1); + const int h = qNextPowerOfTwo(tmp.height() - 1); + if (tmp.width() != w || tmp.height() != h) { + tmp = tmp.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + q->m_texture_size = tmp.size(); + } + } + bool needsRebuild = q->m_texture && q->m_texture->pixelSize() != q->m_texture_size; if (mipmappingChanged) { diff --git a/src/quick/scenegraph/util/qsgtexturematerial.cpp b/src/quick/scenegraph/util/qsgtexturematerial.cpp index a154ae269a..df4e5cfde2 100644 --- a/src/quick/scenegraph/util/qsgtexturematerial.cpp +++ b/src/quick/scenegraph/util/qsgtexturematerial.cpp @@ -164,6 +164,7 @@ void QSGOpaqueTextureMaterialRhiShader::updateSampledImage(const RenderState &st if (isNpot) { t->setHorizontalWrapMode(QSGTexture::ClampToEdge); t->setVerticalWrapMode(QSGTexture::ClampToEdge); + t->setMipmapFiltering(QSGTexture::None); } } -- cgit v1.2.3 From 7629c8de575205ba34b2be42e4c0aebaabb6876a Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 9 Aug 2019 12:44:54 +0200 Subject: Add an initial set of scenegraph docs for the rhi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just the basics for now. Start moving away of the assumption of default backend = direct OpenGL, but limit the amount of RHI-specific details for now. This should be sufficient for the first preview in 5.14. Change-Id: I94e80d5fbed1269f7e8911284c28ac5fbc858be7 Reviewed-by: Christian Strømme --- .../doc/src/concepts/visualcanvas/adaptations.qdoc | 58 +++- .../doc/src/concepts/visualcanvas/scenegraph.qdoc | 312 +++++++++++++-------- src/quick/doc/src/concepts/visualcanvas/topic.qdoc | 17 +- src/quick/doc/src/examples.qdoc | 3 + src/quick/items/qquickwindow.cpp | 4 +- 5 files changed, 257 insertions(+), 137 deletions(-) diff --git a/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc b/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc index 8edc5cb0b6..e83aa39734 100644 --- a/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc +++ b/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc @@ -31,15 +31,35 @@ \section1 Scene Graph Adaptations in Qt Quick -Originally, Qt Quick always relied on OpenGL (OpenGL ES 2.0 or OpenGL 2.0) to parse the scene graph -and render the results to a render target. From Qt 5.8 onwards, Qt Quick also supports rendering in -software and with Direct3D 12. +Originally, Qt Quick always relied on OpenGL (OpenGL ES 2.0 or OpenGL 2.0) to +parse the scene graph and render the results to a render target + +From Qt 5.8 onwards, Qt Quick also supports rendering in software, with OpenVG, +and with Direct3D 12. This is realized by having additional scene graph +adaptations, either in form of plugins (d3d12, openvg) or built-in to the Qt +Quick library (software). The default adaptation continues to rely directly on +OpenGL. + +From Qt 5.14 onwards, the default adaptation gains the option of rendering via +a graphics abstraction layer, the Qt Rendering Hardware Interface (RHI), +provided by the \l QtGui module. When enabled, no direct OpenGL calls are made. +Rather, the scene graph renders by using the APIs provided by the abstraction +layer, which is then translated into OpenGL, Vulkan, Metal, or Direct 3D calls. +Shader handling is also unified by writing shader code once, compiling to +\l{https://www.khronos.org/spir/}{SPIR-V}, and then translating to the language +appropriate for the various graphics APIs. \target Switching Between the Adaptation Used by the Application \section1 Switch Between Adaptations in Your Application -The default rendering backend is still OpenGL, but in Qt builds with OpenGL support disabled, the -default is the software renderer. You can override this in one of two ways: +Unlike \c software or \c d3d12, the RHI-based renderer is not an additional +adaptation, and is always built-in. As of Qt 5.14 it can be enabled by setting +the environment variable \c{QSG_RHI} to a non-zero value before starting the +application, or via \l QQuickWindow::setScenegraphBackend() in combination with +\l QSGRendererInterface::GraphicsApi. When none of this is done, OpenGL is used +directly like in previous versions. + +Switching to a different adaptation can be achieved in two ways: \list \li Use an environment variable - Set the \c{QT_QUICK_BACKEND} or the legacy @@ -51,7 +71,8 @@ default is the software renderer. You can override this in one of two ways: The following backends are supported: \list - \li OpenGL - Request with the \c{""} string or the QSGRendererInterface::OpenGL enum value. + \li Default - Request with the \c{""} string or a QSGRendererInterface::GraphicsApi enum value + different than the ones listed below. \li Software - Request with the \c{"software"} string or the QSGRendererInterface::Software enum value. \li Direct3D 12 - Request with the \c{"d3d12"} string or the QSGRendererInterface::Direct3D12 @@ -64,16 +85,25 @@ To find out which backend is in use, you can enable basic scene graph informatio \c{QSG_INFO} environment variable or the \c{qt.scenegraph.general} logging category. This results in some information being printed onto the debug output, during application startup. -\note Typically, adaptations other than OpenGL come with a set of limitations as they are unlikely - to provide a feature set that's 100% compatible with OpenGL. However, these adaptations may - provide their own specific advantages in certain areas. For more information on the various - adaptations, refer to the sections below. +\note In Qt builds with OpenGL disabled, the default adaptation is \c software. +This may change in future releases. + +\note Typically, adaptations other than the default one come with a set of +limitations as they are unlikely to provide a feature set that's 100% +compatible with OpenGL. However, these adaptations may provide their own +specific advantages in certain areas. For more information on the various +adaptations, refer to the sections below. + +\section1 Default Adaptation -\section1 OpenGL ES 2.0 and OpenGL 2.0 Adaptation +When using OpenGL directly, the default adaptation is capable of providing the +full Qt Quick 2 feature set. For more details, see +\l{qtquick-visualcanvas-scenegraph-renderer.html}{Default Adaptation}. -The OpenGL adaptation is the default adaptation, which is capable of providing the full Qt Quick 2 -feature set. For more details, see -\l{qtquick-visualcanvas-scenegraph-renderer.html}{OpenGL Adaptation}. +When using OpenGL, Vulkan, Metal, or Direct 3D via the RHI, the default +adaptation is capable of providing most features, including the full batching +renderer described in \l{qtquick-visualcanvas-scenegraph-renderer.html}{Default +Adaptation}, but some additional features may not be available as of Qt 5.14. \section1 Software Adaptation diff --git a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc index ee6c501c71..b96d09996d 100644 --- a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc +++ b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc @@ -31,15 +31,13 @@ \section1 The Scene Graph in Qt Quick -Qt Quick 2 makes use of a dedicated scene graph based and a series of -adaptations of which the default uses OpenGL ES 2.0 or OpenGL 2.0 for -its rendering. Using a scene graph for graphics rather than the -traditional imperative painting systems (QPainter and -similar), means the scene to be rendered can be retained between -frames and the complete set of primitives to render is known before -rendering starts. This opens up for a number of optimizations, such as -batch rendering to minimize state changes and discarding obscured -primitives. +Qt Quick 2 makes use of a dedicated scene graph that is then traversed and +rendered via a graphics API such as OpenGL ES, OpenGL, Vulkan, Metal, or Direct +3D. Using a scene graph for graphics rather than the traditional imperative +painting systems (QPainter and similar), means the scene to be rendered can be +retained between frames and the complete set of primitives to render is known +before rendering starts. This opens up for a number of optimizations, such as +batch rendering to minimize state changes and discarding obscured primitives. For example, say a user-interface contains a list of ten items where each item has a background color, an icon and a text. Using the @@ -63,9 +61,10 @@ independently of the state of the items. On many platforms, the scene graph will even be rendered on a dedicated render thread while the GUI thread is preparing the next frame's state. -\note Much of the information listed on this page is specific to the -default OpenGL adaptation of the Qt Quick Scene graph. For more information -about the different scene graph adaptations see +\note Much of the information listed on this page is specific to the built-in, +default behavior of the Qt Quick Scene graph. When using an alternative scene +graph adaptation, such as, the \c software adaptation, not all concepts may +apply. For more information about the different scene graph adaptations see \l{qtquick-visualcanvas-adaptations.html}{Scene Graph Adaptations}. @@ -106,10 +105,10 @@ Custom nodes are added to the scene graph by subclassing QQuickItem::updatePaintNode() and setting the \l {QQuickItem::ItemHasContents} flag. -\warning It is crucial that OpenGL operations and interaction with the -scene graph happens exclusively on the render thread, primarily -during the updatePaintNode() call. The rule of thumb is to only -use classes with the "QSG" prefix inside the +\warning It is crucial that native graphics (OpenGL, Vulkan, Metal, etc.) +operations and interaction with the scene graph happens exclusively on the +render thread, primarily during the updatePaintNode() call. The rule of thumb +is to only use classes with the "QSG" prefix inside the QQuickItem::updatePaintNode() function. For more details, see the \l {Scene Graph - Custom Geometry}. @@ -133,11 +132,11 @@ simplifies cleanup when the scene graph lives outside the GUI thread. \section2 Materials -The material describes how the interior of a geometry in a \l -QSGGeometryNode is filled. It encapsulates an OpenGL shader program -and provides ample flexibility in what can be achieved, though most of -the Qt Quick items themselves only use very basic materials, such as -solid color and texture fills. +The material describes how the interior of a geometry in a \l QSGGeometryNode +is filled. It encapsulates graphics shaders for the vertex and fragment stages +of the graphics pipeline and provides ample flexibility in what can be +achieved, though most of the Qt Quick items themselves only use very basic +materials, such as solid color and texture fills. For users who just want to apply custom shading to a QML Item type, it is possible to do this directly in QML using the \l ShaderEffect @@ -151,11 +150,11 @@ For more details, see the \l {Scene Graph - Simple Material} \section2 Convenience Nodes -The scene graph API is very low-level and focuses on performance -rather than convenience. Writing custom geometries and materials from -scratch, even the most basic ones, requires a non-trivial amount of -code. For this reason, the API includes a few convenience classes to -make the most common custom nodes readily available. +The scene graph API is low-level and focuses on performance rather than +convenience. Writing custom geometries and materials from scratch, even the +most basic ones, requires a non-trivial amount of code. For this reason, the +API includes a few convenience classes to make the most common custom nodes +readily available. \list \li \l QSGSimpleRectNode - a QSGGeometryNode subclass which defines a @@ -169,15 +168,16 @@ a rectangular geometry with a texture material. \section1 Scene Graph and Rendering -The rendering of the scene graph happens internally in the -QQuickWindow class, and there is no public API to access it. There are, -however, a few places in the rendering pipeline where the user can -attach application code. This can be used to add custom scene graph -content or render raw OpenGL content. The integration points are -defined by the render loop. +The rendering of the scene graph happens internally in the QQuickWindow class, +and there is no public API to access it. There are, however, a few places in +the rendering pipeline where the user can attach application code. This can be +used to add custom scene graph content or to insert arbitrary rendering +commands by directly calling the graphics API (OpenGL, Vulkan, Metal, etc.) +that is in use by the scene graph. The integration points are defined by the +render loop. -For detailed description of how the scene graph renderer for OpenGL -works, see \l {Qt Quick Scene Graph OpenGL Renderer}. +For detailed description of how the scene graph renderer works, see \l {Qt +Quick Scene Graph Default Renderer}. There are three render loop variants available: \c basic, \c windows, and \c threaded. Out of these, \c basic and \c windows are @@ -189,14 +189,14 @@ satisfactory, or for testing purposes, the environment variable verify which render loop is in use, enable the \c qt.scenegraph.general \l {QLoggingCategory}{logging category}. -\note The \c threaded and \c windows render loops rely on the OpenGL -implementation for throttling by requesting a swap interval of 1. Some -graphics drivers allow users to override this setting and turn it off, -ignoring Qt's request. Without blocking in the swap buffers operation -(or elsewhere), the render loop will run animations too fast and spin -the CPU at 100%. If a system is known to be unable to provide -vsync-based throttling, use the \c basic render loop instead by -setting \c {QSG_RENDER_LOOP=basic} in the environment. +\note The \c threaded and \c windows render loops rely on the graphics API +implementation for throttling, for example, by requesting a swap interval of 1 +in case of OpenGL. Some graphics drivers allow users to override this setting +and turn it off, ignoring Qt's request. Without blocking in the swap buffers +operation (or elsewhere), the render loop will run animations too fast and spin +the CPU at 100%. If a system is known to be unable to provide vsync-based +throttling, use the \c basic render loop instead by setting \c +{QSG_RENDER_LOOP=basic} in the environment. \section2 Threaded Render Loop ("threaded") @@ -207,8 +207,9 @@ waiting for a blocking swap buffer call. This offers significant performance improvements, but imposes certain restrictions on where and when interaction with the scene graph can happen. -The following is a simple outline of how a frame gets -composed with the threaded render loop. +The following is a simple outline of how a frame gets rendered with the +threaded render loop and OpenGL. The steps are the same with other graphics +APIs as well, apart from the OpenGL context specifics. \image sg-renderloop-threaded.png @@ -219,8 +220,8 @@ to be called. This can be the result of for instance an animation or user input. An event is posted to the render thread to initiate a new frame. -\li The render thread prepares to draw a new frame and makes the -OpenGL context current and initiates a block on the GUI thread. +\li The render thread prepares to draw a new frame and initiates a block on the +GUI thread. \li While the render thread is preparing the new frame, the GUI thread calls QQuickItem::updatePolish() to do final touch-up of items before @@ -243,23 +244,27 @@ time the QML items and the nodes in the scene graph interact. \li The scene graph is rendered: \list 1 - \li The QQuickWindow::beforeRendering() signal is - emitted. Applications can make direct connections - (using Qt::DirectConnection) to this signal to use custom OpenGL calls - which will then stack visually beneath the QML scene. + \li The QQuickWindow::beforeRendering() signal is emitted. Applications can + make direct connections (using Qt::DirectConnection) to this signal to use + custom graphics API calls which will then stack visually beneath the QML + scene. \li Items that have specified QSGNode::UsePreprocess, will have their QSGNode::preprocess() function invoked. - \li The renderer processes the nodes and calls OpenGL functions. + \li The renderer processes the nodes. - \li The QQuickWindow::afterRendering() signal is - emitted. Applications can make direct connections - (using Qt::DirectConnection) to this signal to use custom OpenGL calls - which will then stack visually over the QML scene. + \li The renderer generates states and records draw calls for the graphics + API in use. - \li The rendered frame is swapped and QQuickWindow::frameSwapped() - is emitted. + \li The QQuickWindow::afterRendering() signal is emitted. Applications can + make direct connections (using Qt::DirectConnection) to this signal to + issue custom graphics API calls which will then stack visually over the QML + scene. + + \li The frame is now ready. The buffers are swapped (OpenGL), or a present + command is recorded and the command buffers are submitted to a graphics + queue (Vulkan, Metal). QQuickWindow::frameSwapped() is emitted. \endlist @@ -269,37 +274,38 @@ animations, process events, etc. \endlist The threaded renderer is currently used by default on Windows with -opengl32.dll, Linux with non-Mesa based drivers, mobile -platforms, and Embedded Linux with EGLFS but this is subject to -change. It is possible to force use of the threaded renderer by -setting \c {QSG_RENDER_LOOP=threaded} in the environment. +opengl32.dll, Linux excluding Mesa llvmpipe, \macos with Metal, mobile +platforms, and Embedded Linux with EGLFS, and with Vulkan regardless of the +platform, but this is subject to change. It is always possible to force use of +the threaded renderer by setting \c {QSG_RENDER_LOOP=threaded} in the +environment. \section2 Non-threaded Render Loops ("basic" and "windows") -The non-threaded render loop is currently used by default on Windows -with ANGLE or a non-default opengl32 implementation, \macos, and Linux with -Mesa drivers. For the latter this is mostly a precautionary measure, -as not all combinations of OpenGL drivers and windowing systems have -been tested. At the same time implementations like ANGLE or Mesa -llvmpipe are not able to function properly with threaded rendering at -all so not using threaded rendering is essential for these. +The non-threaded render loop is currently used by default on Windows with ANGLE +or a non-default opengl32 implementation, \macos with OpenGL, and Linux with +some drivers. For the latter this is mostly a precautionary measure, as not all +combinations of OpenGL drivers and windowing systems have been tested. At the +same time implementations like ANGLE or Mesa llvmpipe are not able to function +properly with threaded rendering at all so not using threaded rendering is +essential for these. -On macOS, the threaded render loop is not supported when building -with XCode 10 (10.14 SDK) or later, since this opts in to layer-backed -views on macOS 10.14. You can build with Xcode 9 (10.13 SDK) to opt -out of layer-backing, in which case the threaded render loop is -available and used by default. +On macOS and OpenGL, the threaded render loop is not supported when building +with XCode 10 (10.14 SDK) or later, since this opts in to layer-backed views on +macOS 10.14. You can build with Xcode 9 (10.13 SDK) to opt out of +layer-backing, in which case the threaded render loop is available and used by +default. There is no such restriction with Metal. -By default \c windows is used for non-threaded rendering on Windows -with ANGLE, while \c basic is used for all other platforms when -non-threaded rendering is needed. +By default \c windows is used for non-threaded rendering on Windows with ANGLE, +while \c basic is used for all other platforms when non-threaded rendering is +needed. -Even when using the non-threaded render loop, you should write your -code as if you are using the threaded renderer, as failing to do so -will make the code non-portable. +Even when using the non-threaded render loop, you should write your code as if +you are using the threaded renderer, as failing to do so will make the code +non-portable. -The following is a simplified illustration of the frame rendering -sequence in the non-threaded renderer. +The following is a simplified illustration of the frame rendering sequence in +the non-threaded renderer. \image sg-renderloop-singlethreaded.png @@ -314,32 +320,37 @@ time. It is possible to implement either a threaded or non-threaded behavior similar to the ones shown above. -\section2 Mixing Scene Graph and OpenGL +\section2 Mixing Scene Graph and the native graphics API -The scene graph offers two methods for integrating OpenGL content: -by calling OpenGL commands directly and by creating a textured node -in the scene graph. +The scene graph offers two methods for integrating application-provided +graphics commands: by issuing OpenGL, Vulkan, Metal, etc. commands directly, +and by creating a textured node in the scene graph. By connecting to the \l QQuickWindow::beforeRendering() and \l -QQuickWindow::afterRendering() signals, applications can make OpenGL -calls directly into the same context as the scene graph is rendering -to. As the signal names indicate, the user can then render OpenGL -content either under a Qt Quick scene or over it. The benefit of -integrating in this manner is that no extra framebuffer nor memory is -needed to perform the rendering. The downside is that Qt Quick decides -when to call the signals and this is the only time the OpenGL -application is allowed to draw. +QQuickWindow::afterRendering() signals, applications can make OpenGL calls +directly into the same context as the scene graph is rendering to. With APIs +like Vulkan or Metal, applications can query native objects, such as, the scene +graph's command buffer, via QSGRendererInterface, and record commands to it as +they see fit. As the signal names indicate, the user can then render content +either under a Qt Quick scene or over it. The benefit of integrating in this +manner is that no extra framebuffer nor memory is needed to perform the +rendering, and a possibly expensive texturing step is eliminated. The downside +is that Qt Quick decides when to call the signals and this is the only time the +OpenGL application is allowed to draw. The \l {Scene Graph - OpenGL Under QML} example gives an example on -how to use these signals. +how to use these signals using OpenGL. + +The \l {Scene Graph - Metal Under QML} example gives an example on +how to use these signals using Metal. -The other alternative is to create a QQuickFramebufferObject, render -into it, and let it be displayed in the scene graph as a texture. -The \l {Scene Graph - Rendering FBOs} example shows how this can be -done. It is also possible to combine multiple rendering contexts and -multiple threads to create content to be displayed in the scene graph. -The \l {Scene Graph - Rendering FBOs in a thread} examples show how -this can be done. +The other alternative, only available for OpenGL currently, is to create a +QQuickFramebufferObject, render into it, and let it be displayed in the scene +graph as a texture. The \l {Scene Graph - Rendering FBOs} example shows how +this can be done. It is also possible to combine multiple rendering contexts +and multiple threads to create content to be displayed in the scene graph. The +\l {Scene Graph - Rendering FBOs in a thread} examples show how this can be +done. \warning When mixing OpenGL content with scene graph rendering, it is important the application does not leave the OpenGL context in a state @@ -347,8 +358,8 @@ with buffers bound, attributes enabled, special values in the z-buffer or stencil-buffer or similar. Doing so can result in unpredictable behavior. -\warning The OpenGL rendering code must be thread aware, as the -rendering might be happening outside the GUI thread. +\warning The custom rendering code must be thread aware in the sense that it +should not assume being executed on the GUI (main) thread of the application. \section2 Custom Items using QPainter @@ -386,6 +397,15 @@ addition to being helpful to Qt contributors. \endlist +The legacy \c{QSG_INFO} environment variable is also available. Setting it to a +non-zero value enables the \c{qt.scenegraph.general} category. + +\note When encountering graphics problems, or when in doubt which render loop +or graphics API is in use, always start the application with at least +\c{qt.scenegraph.general} and \c{qt.rhi.*} enabled, or \c{QSG_INFO=1} set. This +will then print some essential information onto the debug output during +initialization. + \section1 Scene Graph Backend In addition to the public API, the scene graph has an adaptation layer @@ -419,13 +439,12 @@ with multiple windows. */ /*! - \title Qt Quick Scene Graph OpenGL Renderer + \title Qt Quick Scene Graph Default Renderer \page qtquick-visualcanvas-scenegraph-renderer.html - This document explains how the scene graph renderer for OpenGL - works internally + This document explains how the default scene graph renderer works internally, so that one can write code that uses it in an optimal fashion, both - performance-wise and feature-wise. + performance and feature-wise. One does not need to understand the internals of the renderer to get good performance. However, it might help when integrating with the @@ -442,8 +461,8 @@ with multiple windows. platforms be processed and rendered in a separate thread. The renderer is a self contained part of the scene graph which traverses the QSGNode tree and uses geometry defined in QSGGeometryNode and - shader state defined in QSGMaterial to schedule OpenGL state change - and draw calls. + shader state defined in QSGMaterial to update the graphics state and + generate draw calls. If needed, the renderer can be completely replaced using the internal scene graph back-end API. This is mostly interesting for @@ -457,11 +476,15 @@ with multiple windows. \section1 Batching - Where a traditional 2D API, such as QPainter, Cairo or Context2D, is - written to handle thousands of individual draw calls per frame, - OpenGL is a pure hardware API and performs best when the number of - draw calls is very low and state changes are kept to a - minimum. Consider the following use case: + Whereas a traditional 2D API, such as QPainter, Cairo or Context2D, is + written to handle thousands of individual draw calls per frame, OpenGL and + other hardware accelerated APIs perform best when the number of draw calls is + very low and state changes are kept to a minimum. + + \note While \c OpenGL is used as an example in the following sections, the + same concepts apply to other graphics APIs as well. + + Consider the following use case: \image visualcanvas_list.png @@ -934,4 +957,65 @@ with multiple windows. \image visualize-overdraw-1.png "overdraw-1" \image visualize-overdraw-2.png "overdraw-2" \c QSG_VISUALIZE=overdraw + + \section1 Rendering via the Qt Rendering Hardware Interface + + From Qt 5.14 onwards, the default adaptation gains the option of rendering + via a graphics abstraction layer, the Qt Rendering Hardware Interface (RHI), + provided by the \l QtGui module. When enabled, no direct OpenGL calls are + made. Rather, the scene graph renders by using the APIs provided by the + abstraction layer, which is then translated into OpenGL, Vulkan, Metal, or + Direct 3D calls. Shader handling is also unified by writing shader code once, + compiling to \l{https://www.khronos.org/spir/}{SPIR-V}, and then translating + to the language appropriate for the various graphics APIs. + + To enable this instead of directly using OpenGL, the following environment + variables can be used: + + \table 100% + \header + \li Environment Variable + \li Possible Values + \li Description + + \row + \li \c QSG_RHI + \li \c 1 + \li Enables rendering via the RHI. The targeted graphics API is chosen based on + the platform, unless overridden by \c QSG_RHI_BACKEND. The defaults are currently + Direct3D 11 for Windows, Metal for macOS, OpenGL elsehwere. + + \row + \li \c QSG_RHI_BACKEND + \li \c vulkan, \c metal, \c opengl, \c d3d11 + \li Requests the specific RHI backend. + + \row + \li \c QSG_INFO + \li \c 1 + \li Like with the OpenGL-based rendering path, setting this enables printing system + information when initializing the Qt Quick scene graph. This can be very useful for + troubleshooting. + + \row + \li \c QSG_RHI_DEBUG_LAYER + \li \c 1 + \li Where applicable (Vulkan, Direct3D), enables the graphics API implementation's debug + and/or validation layers, if available. + + \endtable + + Applications wishing to always run with a single given graphics API, can + request this via C++ as well. For example, the following call made early in + main(), before constructing any QQuickWindow, forces the use of Vulkan (and + will fail otherwise); + + \badcode + QQuickWindow::setSceneGraphBackend(QSGRendererInterface::VulkanRhi); + \endcode + + See QSGRendererInterface::GraphicsApi. The enum values ending in \c Rhi are + equivalent in effect to running with both \c QSG_RHI and \c QSG_RHI_BACKEND + set. + */ diff --git a/src/quick/doc/src/concepts/visualcanvas/topic.qdoc b/src/quick/doc/src/concepts/visualcanvas/topic.qdoc index cb6b3564f2..677e5bd739 100644 --- a/src/quick/doc/src/concepts/visualcanvas/topic.qdoc +++ b/src/quick/doc/src/concepts/visualcanvas/topic.qdoc @@ -56,12 +56,15 @@ See the documentation about the \l{qtquick-visualcanvas-visualparent.html} \section1 Scene Graph Modern computer systems and devices use graphics processing units or GPUs to -render graphics. Qt Quick can leverage this graphics hardware by using graphics -APIs like OpenGL. The default graphics adaptation for Qt Quick requires OpenGL and -it is used to display applications developed with Qt Quick in QML. In particular, -Qt Quick defines a scene graph which is then rendered. See the documentation about the -\l{qtquick-visualcanvas-scenegraph.html}{Scene Graph} for in-depth information about -the concept of a scene graph and why it is beneficial, and about the scene graph -adaptations provided by Qt Quick. +render graphics. Qt Quick can leverage this graphics hardware by using graphics +APIs like \l{https://www.khronos.org/opengl/}{OpenGL}, +\l{https://www.khronos.org/vulkan/}{Vulkan}, or +\l{https://developer.apple.com/documentation/metal}{Metal}. The default +graphics adaptation for Qt Quick requires OpenGL and it is used to display +applications developed with Qt Quick in QML. In particular, Qt Quick defines a +scene graph which is then rendered. See the documentation about the +\l{qtquick-visualcanvas-scenegraph.html}{Scene Graph} for in-depth information +about the concept of a scene graph and why it is beneficial, and about the +scene graph adaptations provided by Qt Quick. */ diff --git a/src/quick/doc/src/examples.qdoc b/src/quick/doc/src/examples.qdoc index 77475e9812..9034c90eb8 100644 --- a/src/quick/doc/src/examples.qdoc +++ b/src/quick/doc/src/examples.qdoc @@ -172,12 +172,15 @@ Creator. \b{Scene Graph} \list \li \l{Scene Graph - OpenGL Under QML}{OpenGL Under QML} + \li \l{Scene Graph - Metal Under QML}{Metal Under QML} + \li \l{Scene Graph - Direct3D 11 Under QML}{Direct3D 11 Under QML} \li \l{Scene Graph - Painted Item}{Painted Item} \li \l{Scene Graph - Custom Geometry}{Custom Geometry} \li \l{Scene Graph - Graph}{Graph} \li \l{Scene Graph - Simple Material}{Simple Material} \li \l{Scene Graph - Rendering FBOs}{Rendering FBOs} \li \l{Scene Graph - Rendering FBOs in a thread}{Rendering FBOs in a thread} + \li \l{Scene Graph - Custom Rendering with QSGRenderNode}{Render Node} \endlist \enddiv \enddiv diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 79db297df8..88a731b229 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -4224,7 +4224,7 @@ QQmlIncubationController *QQuickWindow::incubationController() const When not running with the RHI (and using OpenGL directly), the signal is emitted after the renderer has cleared the render target. This makes it - possible to create appliations that function identically both with and + possible to create applications that function identically both with and without the RHI. \note Resource updates (uploads, copies) typically cannot be enqueued from @@ -4255,7 +4255,7 @@ QQmlIncubationController *QQuickWindow::incubationController() const When not running with the RHI (and using OpenGL directly), the signal is emitted after the renderer has finished its rendering, but before - afterRendering(). This makes it possible to create appliations that + afterRendering(). This makes it possible to create applications that function identically both with and without the RHI. \note Resource updates (uploads, copies) typically cannot be enqueued from -- cgit v1.2.3 From fc820ca49432ca8e621a242d9ce5925012a10c7d Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 16 Aug 2019 10:14:49 +0200 Subject: qmllint: Fail on recursion depth errors Change-Id: I815f82ed8c005ed83ceecff6ce80106a9ad9b21d Reviewed-by: Simon Hausmann Reviewed-by: Fabian Kosmale --- tools/qmllint/findunqualified.cpp | 7 ++++++- tools/qmllint/findunqualified.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/qmllint/findunqualified.cpp b/tools/qmllint/findunqualified.cpp index 0d1cbf5823..0452dae627 100644 --- a/tools/qmllint/findunqualified.cpp +++ b/tools/qmllint/findunqualified.cpp @@ -333,7 +333,9 @@ void FindUnqualifiedIDVisitor::importExportedNames(QStringRef prefix, QString na void FindUnqualifiedIDVisitor::throwRecursionDepthError() { - return; + m_colorOut.write(QStringLiteral("Error"), Error); + m_colorOut.write(QStringLiteral("Maximum statement or expression depth exceeded"), Error); + m_visitFailed = true; } bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiProgram *) @@ -568,6 +570,9 @@ FindUnqualifiedIDVisitor::~FindUnqualifiedIDVisitor() = default; bool FindUnqualifiedIDVisitor::check() { + if (m_visitFailed) + return false; + // now that all ids are known, revisit any Connections whose target were perviously unknown for (auto const& outstandingConnection: m_outstandingConnections) { auto metaObject = m_qmlid2meta[outstandingConnection.targetName]; diff --git a/tools/qmllint/findunqualified.h b/tools/qmllint/findunqualified.h index 8fc8257bef..181f42f265 100644 --- a/tools/qmllint/findunqualified.h +++ b/tools/qmllint/findunqualified.h @@ -59,6 +59,7 @@ private: QSet> m_alreadySeenImports; QSet m_unknownImports; ColorOutput m_colorOut; + bool m_visitFailed = false; struct OutstandingConnection {QString targetName; ScopeTree *scope; QQmlJS::AST::UiObjectDefinition *uiod;}; -- cgit v1.2.3 From ac78adffa9886ab025138e2c44ce5a789f5a6ee6 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Fri, 16 Aug 2019 11:24:24 +0200 Subject: qmllint: do not warn about the identifier of a catch statement Change-Id: I2e679fe4fbebff7d8252da6ea69aed3cc9ffab41 Reviewed-by: Ulf Hermann --- tests/auto/qml/qmllint/data/CatchStatement.qml | 8 ++++++++ .../auto/qml/qmllint/data/catchIdentifierNoWarning.qml | 7 +++++++ tests/auto/qml/qmllint/main.cpp | 18 +++++++++++++++++- tools/qmllint/findunqualified.cpp | 3 ++- 4 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 tests/auto/qml/qmllint/data/CatchStatement.qml create mode 100644 tests/auto/qml/qmllint/data/catchIdentifierNoWarning.qml diff --git a/tests/auto/qml/qmllint/data/CatchStatement.qml b/tests/auto/qml/qmllint/data/CatchStatement.qml new file mode 100644 index 0000000000..e0f70fce7e --- /dev/null +++ b/tests/auto/qml/qmllint/data/CatchStatement.qml @@ -0,0 +1,8 @@ +import QtQml 2.12 + +QtObject { + function f() { + try {} catch(err) {} + console.log(err); + } +} diff --git a/tests/auto/qml/qmllint/data/catchIdentifierNoWarning.qml b/tests/auto/qml/qmllint/data/catchIdentifierNoWarning.qml new file mode 100644 index 0000000000..097baa6fcf --- /dev/null +++ b/tests/auto/qml/qmllint/data/catchIdentifierNoWarning.qml @@ -0,0 +1,7 @@ +import QtQml 2.12 + +QtObject { + function f() { + try {} catch(err) {console.log(err);} + } +} diff --git a/tests/auto/qml/qmllint/main.cpp b/tests/auto/qml/qmllint/main.cpp index 928575bc82..87b34d83bd 100644 --- a/tests/auto/qml/qmllint/main.cpp +++ b/tests/auto/qml/qmllint/main.cpp @@ -41,6 +41,7 @@ private Q_SLOTS: void testUnqualified(); void testUnqualified_data(); void testUnqualifiedNoSpuriousParentWarning(); + void catchIdentifierNoFalsePositive(); private: QString m_qmllintPath; }; @@ -113,7 +114,8 @@ void TestQmllint::testUnqualified_data() QTest::newRow("SignalHandler2") << QStringLiteral("SignalHandler.qml") << QStringLiteral("onPositionChanged: function(mouse) {...") << 10 << 21; QTest::newRow("SignalHandlerShort1") << QStringLiteral("SignalHandler.qml") << QStringLiteral("onClicked: (mouse) => {...") << 8 << 29; QTest::newRow("SignalHandlerShort2") << QStringLiteral("SignalHandler.qml") << QStringLiteral("onPressAndHold: (mouse) => {...") << 12 << 34; - + // access catch identifier outside catch block + QTest::newRow("CatchStatement") << QStringLiteral("CatchStatement.qml") << QStringLiteral("err") << 6 << 21; } void TestQmllint::testUnqualifiedNoSpuriousParentWarning() @@ -143,6 +145,20 @@ void TestQmllint::testUnqualifiedNoSpuriousParentWarning() } } +void TestQmllint::catchIdentifierNoFalsePositive() +{ + auto qmlImportDir = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath); + QString filename = QLatin1String("catchIdentifierNoWarning.qml"); + filename.prepend(QStringLiteral("data/")); + QStringList args; + args << QStringLiteral("-U") << filename << QStringLiteral("-I") << qmlImportDir; + QProcess process; + process.start(m_qmllintPath, args); + QVERIFY(process.waitForFinished()); + QVERIFY(process.exitStatus() == QProcess::NormalExit); + QVERIFY(process.exitCode() == 0); +} + void TestQmllint::test() { QFETCH(QString, filename); diff --git a/tools/qmllint/findunqualified.cpp b/tools/qmllint/findunqualified.cpp index 0452dae627..7a639c328b 100644 --- a/tools/qmllint/findunqualified.cpp +++ b/tools/qmllint/findunqualified.cpp @@ -451,9 +451,10 @@ void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::CaseBlock *) leaveEnvironment(); } -bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::Catch *) +bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::Catch *catchStatement) { enterEnvironment(ScopeType::JSLexicalScope, "catch"); + m_currentScope->insertJSIdentifier(catchStatement->patternElement->bindingIdentifier.toString(), QQmlJS::AST::VariableScope::Let); return true; } -- cgit v1.2.3 From 218e14a897233af7fc42fd1c39182c7d9ffde594 Mon Sep 17 00:00:00 2001 From: Jarkko Koivikko Date: Fri, 16 Aug 2019 15:05:07 +0300 Subject: qmllint: Fix compiler warning findunqualified.cpp(776) : warning C4172: returning address of local variable or temporary: dbg Change-Id: Ifce7ccdcce9ed629a2a9dd4759620d02804812b7 Reviewed-by: Fabian Kosmale Reviewed-by: Ulf Hermann --- tools/qmllint/findunqualified.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/qmllint/findunqualified.cpp b/tools/qmllint/findunqualified.cpp index 7a639c328b..27939608d7 100644 --- a/tools/qmllint/findunqualified.cpp +++ b/tools/qmllint/findunqualified.cpp @@ -40,7 +40,7 @@ #include #include -QDebug &operator<<(QDebug dbg, const QQmlJS::AST::SourceLocation &loc); +QDebug operator<<(QDebug dbg, const QQmlJS::AST::SourceLocation &loc); static QQmlJS::TypeDescriptionReader createReaderForFile(QString const &filename) { @@ -773,7 +773,7 @@ void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::UiObjectDefinition *) leaveEnvironment(); } -QDebug &operator<<(QDebug dbg, const QQmlJS::AST::SourceLocation &loc) +QDebug operator<<(QDebug dbg, const QQmlJS::AST::SourceLocation &loc) { QDebugStateSaver saver(dbg); dbg.nospace() << loc.startLine; -- cgit v1.2.3 From 72b15698a473cdb95197bab160fcdb5731041d8f Mon Sep 17 00:00:00 2001 From: Tasuku Suzuki Date: Mon, 19 Aug 2019 15:06:05 +0900 Subject: Fix build without features.quick_gridview Change-Id: I35303ee67d5976c54b5672d0e2333e8533552986 Reviewed-by: Paolo Angelelli Reviewed-by: Volker Hilsheimer --- src/quick/items/qquickitemsmodule.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index 4168903205..33c4fae96d 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -481,6 +481,8 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) #if QT_CONFIG(quick_itemview) qmlRegisterUncreatableType(uri, 2, 13, itemViewName, itemViewMessage); qmlRegisterType(uri, 2, 13, "PathView"); +#endif +#if QT_CONFIG(quick_gridview) qmlRegisterType(uri, 2, 13, "GridView"); #endif #if QT_CONFIG(quick_tableview) -- cgit v1.2.3 From 06f5b386e69a9e8c8ad3dfbdea44d18d912c23ea Mon Sep 17 00:00:00 2001 From: Tasuku Suzuki Date: Mon, 19 Aug 2019 01:58:22 +0900 Subject: Fix build without features.qml-delegate-model Change-Id: I362febbb395e1d6d55d4b4aac18c6e8bba90bb0c Reviewed-by: Ulf Hermann --- src/qmlmodels/configure.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qmlmodels/configure.json b/src/qmlmodels/configure.json index 84eefed261..1ccca5e35e 100644 --- a/src/qmlmodels/configure.json +++ b/src/qmlmodels/configure.json @@ -30,7 +30,7 @@ "label": "QML table model", "purpose": "Provides the TableModel QML type.", "section": "QML", - "condition": "features.qml-itemmodel", + "condition": "features.qml-itemmodel && features.qml-delegate-model", "output": [ "privateFeature" ] } }, -- cgit v1.2.3 From 1c59558b03715c6be46650489547c5f9d60d3464 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Mon, 5 Aug 2019 16:03:58 +0200 Subject: Introduce functions to set properties during creation Change-Id: Idd4c8ab9e34b9bc3e00f21d7cf1e4f1a70586e7f Reviewed-by: Ulf Hermann --- src/qml/qml/qqmlapplicationengine.cpp | 18 +++- src/qml/qml/qqmlapplicationengine.h | 1 + src/qml/qml/qqmlapplicationengine_p.h | 1 + src/qml/qml/qqmlcomponent.cpp | 74 +++++++++++++++-- src/qml/qml/qqmlcomponent.h | 2 + src/qml/qml/qqmlcomponent_p.h | 3 + src/quick/items/qquickview.cpp | 18 +++- src/quick/items/qquickview.h | 1 + src/quick/items/qquickview_p.h | 2 + .../tst_qqmlapplicationengine.cpp | 18 ++++ tests/auto/qml/qqmlcomponent/data/allJSONTypes.qml | 9 ++ .../data/variantBasedInitialization.qml | 21 +++++ tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp | 96 ++++++++++++++++++++++ tests/auto/quick/qquickview/tst_qquickview.cpp | 12 +++ 14 files changed, 265 insertions(+), 11 deletions(-) create mode 100644 tests/auto/qml/qqmlcomponent/data/allJSONTypes.qml create mode 100644 tests/auto/qml/qqmlcomponent/data/variantBasedInitialization.qml diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp index e93cfcadb9..d04a89b514 100644 --- a/src/qml/qml/qqmlapplicationengine.cpp +++ b/src/qml/qml/qqmlapplicationengine.cpp @@ -131,7 +131,7 @@ void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c) q->objectCreated(nullptr, c->url()); break; case QQmlComponent::Ready: { - auto newObj = c->create(); + auto newObj = initialProperties.empty() ? c->create() : c->createWithInitialProperties(initialProperties); objects << newObj; QObject::connect(newObj, &QObject::destroyed, q, [&](QObject *obj) { objects.removeAll(obj); }); q->objectCreated(objects.constLast(), c->url()); @@ -278,6 +278,22 @@ void QQmlApplicationEngine::load(const QString &filePath) d->startLoad(QUrl::fromUserInput(filePath, QLatin1String("."), QUrl::AssumeLocalFile)); } +/*! + Sets the initial properties with which the QML component gets initialized after + it gets loaded. + + + \sa QQmlComponent::setInitialProperties + \sa QQmlApplicationEngine::load + \sa QQmlApplicationEngine::loadData + \since 5.14 +*/ +void QQmlApplicationEngine::setInitialProperties(const QVariantMap &initialProperties) +{ + Q_D(QQmlApplicationEngine); + d->initialProperties = initialProperties; +} + /*! Loads the QML given in \a data. The object tree defined by \a data is instantiated immediately. diff --git a/src/qml/qml/qqmlapplicationengine.h b/src/qml/qml/qqmlapplicationengine.h index bb5d6b5d68..2b4de91154 100644 --- a/src/qml/qml/qqmlapplicationengine.h +++ b/src/qml/qml/qqmlapplicationengine.h @@ -66,6 +66,7 @@ public: public Q_SLOTS: void load(const QUrl &url); void load(const QString &filePath); + void setInitialProperties(const QVariantMap &initialProperties); void loadData(const QByteArray &data, const QUrl &url = QUrl()); Q_SIGNALS: diff --git a/src/qml/qml/qqmlapplicationengine_p.h b/src/qml/qml/qqmlapplicationengine_p.h index 7a341847bd..1279e400e8 100644 --- a/src/qml/qml/qqmlapplicationengine_p.h +++ b/src/qml/qml/qqmlapplicationengine_p.h @@ -73,6 +73,7 @@ public: void loadTranslations(const QUrl &rootFile); void finishLoad(QQmlComponent *component); QList objects; + QVariantMap initialProperties; }; QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index fefe2bc685..ed8c41a582 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -350,6 +350,32 @@ void QQmlComponentPrivate::clear() compilationUnit = nullptr; } +QObject *QQmlComponentPrivate::doBeginCreate(QQmlComponent *q, QQmlContext *context) +{ + if (!engine) { + // ###Qt6: In Qt 6, it should be impossible for users to create a QQmlComponent without an engine, and we can remove this check + qWarning("QQmlComponent: Must provide an engine before calling create"); + return nullptr; + } + if (!context) + context = engine->rootContext(); + return q->beginCreate(context); +} + +bool QQmlComponentPrivate::setInitialProperty(QObject *component, const QString& name, const QVariant &value) +{ + QQmlProperty prop(component, name); + auto privProp = QQmlPropertyPrivate::get(prop); + if (!prop.isValid() || !privProp->writeValueProperty(value, nullptr)) { + QQmlError error{}; + error.setUrl(url); + error.setDescription(QLatin1String("Could not set property %1").arg(name)); + state.errors.push_back(error); + return false; + } else + return true; +} + /*! \internal */ @@ -780,18 +806,28 @@ QObject *QQmlComponent::create(QQmlContext *context) { Q_D(QQmlComponent); - if (!d->engine) { - // ###Qt6: In Qt 6, it should be impossible for users to create a QQmlComponent without an engine, and we can remove this check - qWarning("QQmlComponent: Must provide an engine before calling create"); - return nullptr; - } + QObject *rv = d->doBeginCreate(this, context); + if (rv) + completeCreate(); + return rv; +} - if (!context) - context = d->engine->rootContext(); +/*! + Create an object instance of this component, and initialize its toplevel properties according to initalPropertyValues. - QObject *rv = beginCreate(context); - if (rv) + + \sa QQmlComponent::create + \since 5.14 +*/ +QObject *QQmlComponent::createWithInitialProperties(const QVariantMap& initialProperties, QQmlContext *context) +{ + Q_D(QQmlComponent); + + QObject *rv = d->doBeginCreate(this, context); + if (rv) { + setInitialProperties(rv, initialProperties); completeCreate(); + } return rv; } @@ -1067,6 +1103,26 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context, enginePriv->incubate(incubator, forContextData); } +/*! + Set toplevel properties of the component. + + + This method provides advanced control over component instance creation. + In general, programmers should use + \l QQmlComponent::createWithInitialProperties to create a component. + + Use this method after beginCreate and before completeCreate has been called. + If a provided property does not exist, a warning is issued. + + \since 5.14 +*/ +void QQmlComponent::setInitialProperties(QObject *component, const QVariantMap &properties) +{ + Q_D(QQmlComponent); + for (auto it = properties.constBegin(); it != properties.constEnd(); ++it) + d->setInitialProperty(component, it.key(), it.value()); +} + /* This is essentially a copy of QQmlComponent::create(); except it takes the QQmlContextData arguments instead of QQmlContext which means we don't have to construct the rather weighty diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h index 39b6d4526f..f259c99b08 100644 --- a/src/qml/qml/qqmlcomponent.h +++ b/src/qml/qml/qqmlcomponent.h @@ -100,6 +100,8 @@ public: QUrl url() const; virtual QObject *create(QQmlContext *context = nullptr); + QObject *createWithInitialProperties(const QVariantMap& initialProperties, QQmlContext *context = nullptr); + void setInitialProperties(QObject *component, const QVariantMap &properties); virtual QObject *beginCreate(QQmlContext *); virtual void completeCreate(); diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h index 9a967501c9..2170646b89 100644 --- a/src/qml/qml/qqmlcomponent_p.h +++ b/src/qml/qml/qqmlcomponent_p.h @@ -143,6 +143,9 @@ public: static QQmlComponentPrivate *get(QQmlComponent *c) { return static_cast(QObjectPrivate::get(c)); } + + QObject *doBeginCreate(QQmlComponent *q, QQmlContext *context); + bool setInitialProperty(QObject *component, const QString &name, const QVariant& value); }; QT_END_NAMESPACE diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp index 61477360bf..17fc16d44b 100644 --- a/src/quick/items/qquickview.cpp +++ b/src/quick/items/qquickview.cpp @@ -239,6 +239,22 @@ void QQuickView::setSource(const QUrl& url) d->execute(); } +/*! + Sets the initial properties with which the QML component gets initialized after + calling \l QQuickView::setSource. + + + Note that you can only use this function to initialize toplevel properties. + + \sa QQmlComponent::createWithInitialProperties + \since 5.14 +*/ +void QQuickView::setInitialProperties(const QVariantMap &initialProperties) +{ + Q_D(QQuickView); + d->initialProperties = initialProperties; +} + /*! \internal @@ -471,7 +487,7 @@ void QQuickView::continueExecute() return; } - QObject *obj = d->component->create(); + QObject *obj = d->initialProperties.empty() ? d->component->create() : d->component->createWithInitialProperties(d->initialProperties); if (d->component->isError()) { const QList errorList = d->component->errors(); diff --git a/src/quick/items/qquickview.h b/src/quick/items/qquickview.h index ecae25e90b..4122fcac79 100644 --- a/src/quick/items/qquickview.h +++ b/src/quick/items/qquickview.h @@ -88,6 +88,7 @@ public: public Q_SLOTS: void setSource(const QUrl&); + void setInitialProperties(const QVariantMap &initialProperties); void setContent(const QUrl& url, QQmlComponent *component, QObject *item); Q_SIGNALS: diff --git a/src/quick/items/qquickview_p.h b/src/quick/items/qquickview_p.h index 3f284c0519..b1ab8d8e8c 100644 --- a/src/quick/items/qquickview_p.h +++ b/src/quick/items/qquickview_p.h @@ -108,6 +108,8 @@ public: QQuickView::ResizeMode resizeMode; QSize initialSize; QElapsedTimer frameTimer; + + QVariantMap initialProperties; }; QT_END_NAMESPACE diff --git a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp index 8787a43884..0f5eea8b95 100644 --- a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp +++ b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp @@ -52,6 +52,7 @@ private slots: void removeObjectsWhenDestroyed(); void loadTranslation_data(); void loadTranslation(); + void setInitialProperties(); private: QString buildDir; @@ -275,6 +276,23 @@ void tst_qqmlapplicationengine::loadTranslation() QCOMPARE(rootObject->property("translation").toString(), translation); } +void tst_qqmlapplicationengine::setInitialProperties() +{ + QQmlApplicationEngine test {}; + { + test.setInitialProperties(QVariantMap{{"success", false}}); + test.load(testFileUrl("basicTest.qml")); + QVERIFY(!test.rootObjects().empty()); + QCOMPARE(test.rootObjects().first()->property("success").toBool(), false); + } + { + test.setInitialProperties({{"success", true}}); + test.load(testFileUrl("basicTest.qml")); + QCOMPARE(test.rootObjects().size(), 2); + QCOMPARE(test.rootObjects().at(1)->property("success").toBool(), true); + } +} + QTEST_MAIN(tst_qqmlapplicationengine) #include "tst_qqmlapplicationengine.moc" diff --git a/tests/auto/qml/qqmlcomponent/data/allJSONTypes.qml b/tests/auto/qml/qqmlcomponent/data/allJSONTypes.qml new file mode 100644 index 0000000000..0541c9b104 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/allJSONTypes.qml @@ -0,0 +1,9 @@ +import QtQuick 2.14 + +Item { + property int i + property bool b + property double d + property string s + property var nothing +} diff --git a/tests/auto/qml/qqmlcomponent/data/variantBasedInitialization.qml b/tests/auto/qml/qqmlcomponent/data/variantBasedInitialization.qml new file mode 100644 index 0000000000..acf08e94d2 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/variantBasedInitialization.qml @@ -0,0 +1,21 @@ +import QtQuick 2.14 + +Item { + property int i + property bool b + property double d + property string s + property var nothing + property url myurl + property color c + property font myfont + property date mydate + property point mypoint + property size mysize + property rect myrect + property matrix4x4 matrix + property quaternion quat + property vector2d vec2 + property vector3d vec3 + property vector4d vec4 +} diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp index 71d3e8fe5f..79ec507388 100644 --- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp +++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp @@ -121,6 +121,7 @@ private slots: void relativeUrl_data(); void relativeUrl(); void setDataNoEngineNoSegfault(); + void testSetInitialProperties(); private: QQmlEngine engine; @@ -667,6 +668,101 @@ void tst_qqmlcomponent::setDataNoEngineNoSegfault() QVERIFY(!c); } +void tst_qqmlcomponent::testSetInitialProperties() +{ + QQmlEngine eng; + { + // JSON based initialization + QQmlComponent comp(&eng); + comp.loadUrl(testFileUrl("allJSONTypes.qml")); + QScopedPointer obj { comp.beginCreate(eng.rootContext()) }; + QVERIFY(obj); + comp.setInitialProperties(obj.get(), QVariantMap { + {QLatin1String("i"), 42}, + {QLatin1String("b"), true}, + {QLatin1String("d"), 3.1416}, + {QLatin1String("s"), QLatin1String("hello world")}, + {QLatin1String("nothing"), QVariant::fromValue(nullptr)} + }); + comp.completeCreate(); + if (!comp.errors().empty()) + qDebug() << comp.errorString() << comp.errors(); + QVERIFY(comp.errors().empty()); + QCOMPARE(obj->property("i"), 42); + QCOMPARE(obj->property("b"), true); + QCOMPARE(obj->property("d"), 3.1416); + QCOMPARE(obj->property("s"), QLatin1String("hello world")); + QCOMPARE(obj->property("nothing"), QVariant::fromValue(nullptr)); + } + { + // QVariant + QQmlComponent comp(&eng); + comp.loadUrl(testFileUrl("variantBasedInitialization.qml")); + QScopedPointer obj { comp.beginCreate(eng.rootContext()) }; + QVERIFY(obj); + QUrl myurl = comp.url(); + QFont myfont; + QDateTime mydate = QDateTime::currentDateTime(); + QPoint mypoint {1,2}; + QSizeF mysize {0.5, 0.3}; + QMatrix4x4 matrix {}; + QQuaternion quat {5.0f, 0.3f, 0.2f, 0.1f}; + QVector2D vec2 {2.0f, 3.1f}; + QVector3D vec3 {1.0f, 2.0, 3.0f}; + QVector4D vec4 {1.0f, 2.0f, 3.0f, 4.0f}; +#define ASJSON(NAME) {QLatin1String(#NAME), NAME} + comp.setInitialProperties(obj.get(), QVariantMap { + {QLatin1String("i"), 42}, + {QLatin1String("b"), true}, + {QLatin1String("d"), 3.1416}, + {QLatin1String("s"), QLatin1String("hello world")}, + {QLatin1String("nothing"), QVariant::fromValue( nullptr)}, + ASJSON(myurl), + ASJSON(myfont), + ASJSON(mydate), + ASJSON(mypoint), + ASJSON(mysize), + ASJSON(matrix), + ASJSON(quat), + ASJSON(vec2), ASJSON(vec3), ASJSON(vec4) + }); +#undef ASJSON + comp.completeCreate(); + if (!comp.errors().empty()) + qDebug() << comp.errorString() << comp.errors(); + QVERIFY(comp.errors().empty()); + QCOMPARE(obj->property("i"), 42); + QCOMPARE(obj->property("b"), true); + QCOMPARE(obj->property("d"), 3.1416); + QCOMPARE(obj->property("s"), QLatin1String("hello world")); + QCOMPARE(obj->property("nothing"), QVariant::fromValue(nullptr)); +#define COMPARE(NAME) QCOMPARE(obj->property(#NAME), NAME) + COMPARE(myurl); + COMPARE(myfont); + COMPARE(mydate); + COMPARE(mypoint); + COMPARE(mysize); + COMPARE(matrix); + COMPARE(quat); + COMPARE(vec2); + COMPARE(vec3); + COMPARE(vec4); +#undef COMPARE + + } + { + // createWithInitialProperties: setting a nonexistent property + QQmlComponent comp(&eng); + comp.loadUrl(testFileUrl("allJSONTypes.qml")); + QScopedPointer obj { + comp.createWithInitialProperties(QVariantMap { {"notThePropertiesYoureLookingFor", 42} }) + }; + qDebug() << comp.errorString(); + QVERIFY(obj); + QVERIFY(comp.errorString().contains("Could not set property notThePropertiesYoureLookingFor")); + } +} + QTEST_MAIN(tst_qqmlcomponent) #include "tst_qqmlcomponent.moc" diff --git a/tests/auto/quick/qquickview/tst_qquickview.cpp b/tests/auto/quick/qquickview/tst_qquickview.cpp index e259ed1ae7..dbce0d308c 100644 --- a/tests/auto/quick/qquickview/tst_qquickview.cpp +++ b/tests/auto/quick/qquickview/tst_qquickview.cpp @@ -49,6 +49,7 @@ private slots: void errors(); void engine(); void findChild(); + void setInitialProperties(); }; @@ -283,6 +284,17 @@ void tst_QQuickView::findChild() QVERIFY(!view.rootObject()->findChild("rootObject")); // self } +void tst_QQuickView::setInitialProperties() +{ + QQuickView view; + view.setInitialProperties({{"z", 4}, {"width", 100}}); + view.setSource(testFileUrl("resizemodeitem.qml")); + QObject *rootObject = view.rootObject(); + QVERIFY(rootObject); + QCOMPARE(rootObject->property("z").toInt(), 4); + QCOMPARE(rootObject->property("width").toInt(), 100); +} + QTEST_MAIN(tst_QQuickView) #include "tst_qquickview.moc" -- cgit v1.2.3 From 6b106d446370215918aade9e19bb611f74b19333 Mon Sep 17 00:00:00 2001 From: Tasuku Suzuki Date: Sat, 17 Aug 2019 18:52:02 +0900 Subject: Fix build without features.temporaryfile Change-Id: If990efb64a4117bc7624062fededa7ce6a910f14 Reviewed-by: Ulf Hermann --- tools/qmlcachegen/generateloader.cpp | 6 ++++++ tools/qmlcachegen/qmlcachegen.cpp | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/tools/qmlcachegen/generateloader.cpp b/tools/qmlcachegen/generateloader.cpp index 74208a25e2..1c8a5a016a 100644 --- a/tools/qmlcachegen/generateloader.cpp +++ b/tools/qmlcachegen/generateloader.cpp @@ -434,7 +434,11 @@ bool generateLoader(const QStringList &compiledFiles, const QStringList &sortedR } } +#if QT_CONFIG(temporaryfile) QSaveFile f(outputFileName); +#else + QFile f(outputFileName); +#endif if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) { *errorString = f.errorString(); return false; @@ -445,10 +449,12 @@ bool generateLoader(const QStringList &compiledFiles, const QStringList &sortedR return false; } +#if QT_CONFIG(temporaryfile) if (!f.commit()) { *errorString = f.errorString(); return false; } +#endif return true; } diff --git a/tools/qmlcachegen/qmlcachegen.cpp b/tools/qmlcachegen/qmlcachegen.cpp index cfbd1cd87d..ac9cf039d3 100644 --- a/tools/qmlcachegen/qmlcachegen.cpp +++ b/tools/qmlcachegen/qmlcachegen.cpp @@ -334,7 +334,11 @@ static bool saveUnitAsCpp(const QString &inputFileName, const QString &outputFil const QV4::CompiledData::SaveableUnitPointer &unit, QString *errorString) { +#if QT_CONFIG(temporaryfile) QSaveFile f(outputFileName); +#else + QFile f(outputFileName); +#endif if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) { *errorString = f.errorString(); return false; @@ -392,10 +396,12 @@ static bool saveUnitAsCpp(const QString &inputFileName, const QString &outputFil if (!writeStr("};\n}\n}\n")) return false; +#if QT_CONFIG(temporaryfile) if (!f.commit()) { *errorString = f.errorString(); return false; } +#endif return true; } -- cgit v1.2.3 From f9eedc501d02a3d856c0502c06daef273a2935ca Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Thu, 1 Aug 2019 16:36:10 +0200 Subject: Doc: Correct wrong code in qml snippet Replace QT_TRANSLATE_NOOP with equiv. qStr statement Task-number: QTBUG-56875 Change-Id: I80581ecf05a25e0c69da434d3e548261eac5811e Reviewed-by: Frederik Schwarzer Reviewed-by: Venugopal Shivashankar --- src/quick/doc/src/concepts/positioning/righttoleft.qdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quick/doc/src/concepts/positioning/righttoleft.qdoc b/src/quick/doc/src/concepts/positioning/righttoleft.qdoc index 7c8cd735b3..1f3602cde1 100644 --- a/src/quick/doc/src/concepts/positioning/righttoleft.qdoc +++ b/src/quick/doc/src/concepts/positioning/righttoleft.qdoc @@ -148,7 +148,7 @@ To define the layout direction for a particular locale, declare the dedicated st You can do this by first introducing this line \code -QT_TRANSLATE_NOOP("QGuiApplication", "QT_LAYOUT_DIRECTION"); +qsTr("QT_LAYOUT_DIRECTION","QGuiApplication"); \endcode somewhere in your QML source code and calling \c lupdate to generate the translation source file. -- cgit v1.2.3 From 1535c36a4728b3355ebe8abba4a9966eb2169d27 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Mon, 22 Jul 2019 15:58:17 +0200 Subject: Doc: Correct error in doc Transition QML Type - corrected reference to non-existing state - added example with multiple states Fixes: QTBUG-73982 Change-Id: I7c815cb706f1ad1b8035f136448b75dce8eb9bfe Reviewed-by: Paul Wicking --- src/quick/doc/images/declarative-qtlogo.png | Bin 3436 -> 1214 bytes src/quick/doc/snippets/qml/transitions-list.qml | 135 +++++++++++++++++------- src/quick/util/qquicktransition.cpp | 20 ++-- 3 files changed, 106 insertions(+), 49 deletions(-) diff --git a/src/quick/doc/images/declarative-qtlogo.png b/src/quick/doc/images/declarative-qtlogo.png index 940d159ae4..b63f1384b1 100644 Binary files a/src/quick/doc/images/declarative-qtlogo.png and b/src/quick/doc/images/declarative-qtlogo.png differ diff --git a/src/quick/doc/snippets/qml/transitions-list.qml b/src/quick/doc/snippets/qml/transitions-list.qml index 06b9e39cc8..972d3ee14e 100644 --- a/src/quick/doc/snippets/qml/transitions-list.qml +++ b/src/quick/doc/snippets/qml/transitions-list.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -48,52 +48,105 @@ ** ****************************************************************************/ -import QtQuick 2.0 +import QtQuick 2.13 Rectangle { - width: 150; height: 250 + id: page + width: 640 + height: 500 - Rectangle { - id: stopLight - x: 25; y: 15; width: 100; height: 100 - } - Rectangle { - id: goLight - x: 25; y: 135; width: 100; height: 100 - } + Image { + id: userIcon + x: topLeftRect.x + y: topLeftRect.y - states: [ - State { - name: "stop" - PropertyChanges { target: stopLight; color: "red" } - PropertyChanges { target: goLight; color: "black" } - }, - State { - name: "go" - PropertyChanges { target: stopLight; color: "black" } - PropertyChanges { target: goLight; color: "green" } + source: "../../images/declarative-qtlogo.png" } - ] - state: "stop" + Rectangle { + id: topLeftRect + anchors { left: parent.left; top: parent.top; leftMargin: 10; topMargin: 20 } + width: 46; height: 54 + color: "Transparent"; border.color: "Gray"; radius: 6 + // Clicking here sets state to default state, returning image to initial position + TapHandler { onTapped: page.state = 'start' } + } + + Rectangle { + id: middleRightRect + anchors { right: parent.right; verticalCenter: parent.verticalCenter; rightMargin: 20 } + width: 46; height: 54 + color: "Transparent"; border.color: "Gray"; radius: 6 + // Clicking in here sets the state to 'middleRight' + TapHandler { onTapped: page.state = 'middleRight' } + } - MouseArea { - anchors.fill: parent - onClicked: parent.state == "stop" ? - parent.state = "go" : parent.state = "stop" - } + Rectangle { + id: bottomLeftRect + anchors { left: parent.left; bottom: parent.bottom; leftMargin: 10; bottomMargin: 20 } + width: 46; height: 54 + color: "Transparent"; border.color: "Gray"; radius: 6 + // Clicking in here sets the state to 'bottomLeft' + TapHandler { onTapped: page.state = 'bottomLeft' } + } - //! [list of transitions] - transitions: [ - Transition { - from: "stop"; to: "go" - PropertyAnimation { target: stopLight - properties: "color"; duration: 1000 } - }, - Transition { - from: "go"; to: "stop" - PropertyAnimation { target: goLight - properties: "color"; duration: 1000 } - } ] - //! [list of transitions] + states: [ + State { + name: "start" + PropertyChanges { + target: userIcon + explicit: true + x: topLeftRect.x + y: topLeftRect.y + } + }, + State { + name: "middleRight" + PropertyChanges { + target: userIcon + explicit: true + x: middleRightRect.x + y: middleRightRect.y + } + }, + State { + name: "bottomLeft" + PropertyChanges { + target: userIcon + explicit: true + x: bottomLeftRect.x + y: bottomLeftRect.y + } + } + ] +//! [list of transitions] + transitions: [ + Transition { + from: "*"; to: "middleRight" + NumberAnimation { + properties: "x,y"; + easing.type: Easing.InOutQuad; + duration: 2000; + } + }, + Transition { + from: "*"; to: "bottomLeft"; + NumberAnimation { + properties: "x,y"; + easing.type: Easing.InOutQuad; + duration: 200; + } + }, + //If any other rectangle is clicked, the icon will return + //to the start position at a slow speed and bounce. + Transition { + from: "*"; to: "*"; + NumberAnimation { + easing.type: Easing.OutBounce; + properties: "x,y"; + duration: 4000; + } + } + ] +//! [list of transitions] } diff --git a/src/quick/util/qquicktransition.cpp b/src/quick/util/qquicktransition.cpp index c8699426f2..b973309212 100644 --- a/src/quick/util/qquicktransition.cpp +++ b/src/quick/util/qquicktransition.cpp @@ -82,13 +82,15 @@ QT_BEGIN_NAMESPACE values can be set to restrict the animations to only be applied when changing from one particular state to another. - To define multiple transitions, specify \l Item::transitions as a list: + To define multiple Transitions, specify \l Item::transitions as a list: \snippet qml/transitions-list.qml list of transitions - If multiple Transitions are specified, only a single (best-matching) Transition will be applied for any particular - state change. In the example above, when changing to \c state1, the first transition will be used, rather - than the more generic second transition. + If multiple Transitions are specified, only a single (best-matching) + Transition will be applied for any particular state change. In the + example above, if the Rectangle enters a state other than \c "middleRight" + or \c "bottomLeft", the third Transition will be carried out, meaning the + icon will be moved to the starting point. If a state change has a Transition that matches the same property as a \l Behavior, the Transition animation overrides the \l Behavior for that @@ -298,10 +300,11 @@ QQuickTransitionInstance *QQuickTransition::prepare(QQuickStateOperation::Action \snippet qml/transition-from-to-modified.qml modified transition - The animation would only be applied when changing from the default state to - the "brighter" state (i.e. when the mouse is pressed, but not on release). + The animation would only be applied when changing from the default state + to the "brighter" state (i.e. when the mouse is pressed, but not on release). - Multiple \c to and \c from values can be set by using a comma-separated string. + Multiple \c to and \c from values can be set by using a comma-separated + string. \sa reversible */ @@ -323,7 +326,8 @@ void QQuickTransition::setFromState(const QString &f) /*! \qmlproperty bool QtQuick::Transition::reversible - This property holds whether the transition should be automatically reversed when the conditions that triggered this transition are reversed. + This property holds whether the transition should be automatically + reversed when the conditions that triggered this transition are reversed. The default value is false. -- cgit v1.2.3 From 73a9c52fedf25196ed17d55cd1c6b1c1c9fd991d Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 19 Aug 2019 11:09:48 +0200 Subject: Reference Examples: Use initializer lists to avoid repeating type naems Change-Id: Iff0b31d9b641a55ea246235ba1d7a066592ef0c0 Reviewed-by: Simon Hausmann --- examples/qml/referenceexamples/attached/birthdayparty.cpp | 2 +- examples/qml/referenceexamples/coercion/birthdayparty.cpp | 2 +- examples/qml/referenceexamples/default/birthdayparty.cpp | 2 +- examples/qml/referenceexamples/grouped/birthdayparty.cpp | 2 +- examples/qml/referenceexamples/methods/birthdayparty.cpp | 2 +- examples/qml/referenceexamples/properties/birthdayparty.cpp | 4 ++-- examples/qml/referenceexamples/signal/birthdayparty.cpp | 2 +- examples/qml/referenceexamples/valuesource/birthdayparty.cpp | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/qml/referenceexamples/attached/birthdayparty.cpp b/examples/qml/referenceexamples/attached/birthdayparty.cpp index 26aa56e86c..da0cb800fc 100644 --- a/examples/qml/referenceexamples/attached/birthdayparty.cpp +++ b/examples/qml/referenceexamples/attached/birthdayparty.cpp @@ -81,7 +81,7 @@ void BirthdayParty::setHost(Person *c) QQmlListProperty BirthdayParty::guests() { - return QQmlListProperty(this, m_guests); + return {this, m_guests}; } int BirthdayParty::guestCount() const diff --git a/examples/qml/referenceexamples/coercion/birthdayparty.cpp b/examples/qml/referenceexamples/coercion/birthdayparty.cpp index e729c42bb5..1bae55076c 100644 --- a/examples/qml/referenceexamples/coercion/birthdayparty.cpp +++ b/examples/qml/referenceexamples/coercion/birthdayparty.cpp @@ -66,7 +66,7 @@ void BirthdayParty::setHost(Person *c) QQmlListProperty BirthdayParty::guests() { - return QQmlListProperty(this, m_guests); + return {this, m_guests}; } int BirthdayParty::guestCount() const diff --git a/examples/qml/referenceexamples/default/birthdayparty.cpp b/examples/qml/referenceexamples/default/birthdayparty.cpp index e729c42bb5..1bae55076c 100644 --- a/examples/qml/referenceexamples/default/birthdayparty.cpp +++ b/examples/qml/referenceexamples/default/birthdayparty.cpp @@ -66,7 +66,7 @@ void BirthdayParty::setHost(Person *c) QQmlListProperty BirthdayParty::guests() { - return QQmlListProperty(this, m_guests); + return {this, m_guests}; } int BirthdayParty::guestCount() const diff --git a/examples/qml/referenceexamples/grouped/birthdayparty.cpp b/examples/qml/referenceexamples/grouped/birthdayparty.cpp index e729c42bb5..1bae55076c 100644 --- a/examples/qml/referenceexamples/grouped/birthdayparty.cpp +++ b/examples/qml/referenceexamples/grouped/birthdayparty.cpp @@ -66,7 +66,7 @@ void BirthdayParty::setHost(Person *c) QQmlListProperty BirthdayParty::guests() { - return QQmlListProperty(this, m_guests); + return {this, m_guests}; } int BirthdayParty::guestCount() const diff --git a/examples/qml/referenceexamples/methods/birthdayparty.cpp b/examples/qml/referenceexamples/methods/birthdayparty.cpp index dfb36257eb..f13c500bcf 100644 --- a/examples/qml/referenceexamples/methods/birthdayparty.cpp +++ b/examples/qml/referenceexamples/methods/birthdayparty.cpp @@ -67,7 +67,7 @@ void BirthdayParty::setHost(Person *c) QQmlListProperty BirthdayParty::guests() { - return QQmlListProperty(this, m_guests); + return {this, m_guests}; } int BirthdayParty::guestCount() const diff --git a/examples/qml/referenceexamples/properties/birthdayparty.cpp b/examples/qml/referenceexamples/properties/birthdayparty.cpp index 717c3e0f71..9abb08dbd9 100644 --- a/examples/qml/referenceexamples/properties/birthdayparty.cpp +++ b/examples/qml/referenceexamples/properties/birthdayparty.cpp @@ -67,11 +67,11 @@ void BirthdayParty::setHost(Person *c) QQmlListProperty BirthdayParty::guests() { - return QQmlListProperty(this, this, + return {this, this, &BirthdayParty::appendGuest, &BirthdayParty::guestCount, &BirthdayParty::guest, - &BirthdayParty::clearGuests); + &BirthdayParty::clearGuests}; } void BirthdayParty::appendGuest(Person* p) { diff --git a/examples/qml/referenceexamples/signal/birthdayparty.cpp b/examples/qml/referenceexamples/signal/birthdayparty.cpp index a5fbb742a5..9d34cdf146 100644 --- a/examples/qml/referenceexamples/signal/birthdayparty.cpp +++ b/examples/qml/referenceexamples/signal/birthdayparty.cpp @@ -82,7 +82,7 @@ void BirthdayParty::setHost(Person *c) QQmlListProperty BirthdayParty::guests() { - return QQmlListProperty(this, m_guests); + return {this, m_guests}; } int BirthdayParty::guestCount() const diff --git a/examples/qml/referenceexamples/valuesource/birthdayparty.cpp b/examples/qml/referenceexamples/valuesource/birthdayparty.cpp index b107c61570..68d5767e8d 100644 --- a/examples/qml/referenceexamples/valuesource/birthdayparty.cpp +++ b/examples/qml/referenceexamples/valuesource/birthdayparty.cpp @@ -82,7 +82,7 @@ void BirthdayParty::setHost(Person *c) QQmlListProperty BirthdayParty::guests() { - return QQmlListProperty(this, m_guests); + return {this, m_guests}; } int BirthdayParty::guestCount() const -- cgit v1.2.3 From 66fabff2530f2080c07bcf89a47474daea4c7c38 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 19 Aug 2019 11:04:30 +0200 Subject: Reference Examples: Use auto for results of new and component.create() Change-Id: Ibfd92fbc5a99b38cf8b31a11c0adfdfa69e2bb36 Reviewed-by: Fabian Kosmale Reviewed-by: Simon Hausmann --- examples/qml/referenceexamples/adding/main.cpp | 2 +- examples/qml/referenceexamples/attached/main.cpp | 2 +- examples/qml/referenceexamples/binding/happybirthdaysong.cpp | 2 +- examples/qml/referenceexamples/binding/main.cpp | 2 +- examples/qml/referenceexamples/coercion/main.cpp | 2 +- examples/qml/referenceexamples/default/main.cpp | 2 +- examples/qml/referenceexamples/extended/main.cpp | 2 +- examples/qml/referenceexamples/grouped/main.cpp | 2 +- examples/qml/referenceexamples/methods/birthdayparty.cpp | 2 +- examples/qml/referenceexamples/methods/main.cpp | 2 +- examples/qml/referenceexamples/properties/main.cpp | 2 +- examples/qml/referenceexamples/signal/main.cpp | 2 +- examples/qml/referenceexamples/valuesource/happybirthdaysong.cpp | 2 +- examples/qml/referenceexamples/valuesource/main.cpp | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/examples/qml/referenceexamples/adding/main.cpp b/examples/qml/referenceexamples/adding/main.cpp index 5c3c891130..e312149da1 100644 --- a/examples/qml/referenceexamples/adding/main.cpp +++ b/examples/qml/referenceexamples/adding/main.cpp @@ -62,7 +62,7 @@ int main(int argc, char ** argv) QQmlEngine engine; QQmlComponent component(&engine, QUrl("qrc:example.qml")); - Person *person = qobject_cast(component.create()); + auto *person = qobject_cast(component.create()); if (person) { qWarning() << "The person's name is" << person->name(); qWarning() << "They wear a" << person->shoeSize() << "sized shoe"; diff --git a/examples/qml/referenceexamples/attached/main.cpp b/examples/qml/referenceexamples/attached/main.cpp index f07f16ae0f..581b033dfc 100644 --- a/examples/qml/referenceexamples/attached/main.cpp +++ b/examples/qml/referenceexamples/attached/main.cpp @@ -67,7 +67,7 @@ int main(int argc, char ** argv) QQmlEngine engine; QQmlComponent component(&engine, QUrl("qrc:example.qml")); - BirthdayParty *party = qobject_cast(component.create()); + auto *party = qobject_cast(component.create()); if (party && party->host()) { qWarning() << party->host()->name() << "is having a birthday!"; diff --git a/examples/qml/referenceexamples/binding/happybirthdaysong.cpp b/examples/qml/referenceexamples/binding/happybirthdaysong.cpp index fae016091b..5f8e6d696e 100644 --- a/examples/qml/referenceexamples/binding/happybirthdaysong.cpp +++ b/examples/qml/referenceexamples/binding/happybirthdaysong.cpp @@ -54,7 +54,7 @@ HappyBirthdaySong::HappyBirthdaySong(QObject *parent) : QObject(parent), m_line(-1) { setName(QString()); - QTimer *timer = new QTimer(this); + auto *timer = new QTimer(this); QObject::connect(timer, &QTimer::timeout, this, &HappyBirthdaySong::advance); timer->start(1000); } diff --git a/examples/qml/referenceexamples/binding/main.cpp b/examples/qml/referenceexamples/binding/main.cpp index cc9ce8f373..99187eba3e 100644 --- a/examples/qml/referenceexamples/binding/main.cpp +++ b/examples/qml/referenceexamples/binding/main.cpp @@ -68,7 +68,7 @@ int main(int argc, char ** argv) QQmlEngine engine; QQmlComponent component(&engine, QUrl("qrc:example.qml")); - BirthdayParty *party = qobject_cast(component.create()); + auto *party = qobject_cast(component.create()); if (party && party->host()) { qWarning() << party->host()->name() << "is having a birthday!"; diff --git a/examples/qml/referenceexamples/coercion/main.cpp b/examples/qml/referenceexamples/coercion/main.cpp index 04a78b05f7..262cdf6320 100644 --- a/examples/qml/referenceexamples/coercion/main.cpp +++ b/examples/qml/referenceexamples/coercion/main.cpp @@ -70,7 +70,7 @@ int main(int argc, char ** argv) QQmlEngine engine; QQmlComponent component(&engine, QUrl("qrc:example.qml")); - BirthdayParty *party = qobject_cast(component.create()); + auto *party = qobject_cast(component.create()); if (party && party->host()) { qWarning() << party->host()->name() << "is having a birthday!"; diff --git a/examples/qml/referenceexamples/default/main.cpp b/examples/qml/referenceexamples/default/main.cpp index d8c3e466ce..017d6495cd 100644 --- a/examples/qml/referenceexamples/default/main.cpp +++ b/examples/qml/referenceexamples/default/main.cpp @@ -65,7 +65,7 @@ int main(int argc, char ** argv) QQmlEngine engine; QQmlComponent component(&engine, QUrl("qrc:example.qml")); - BirthdayParty *party = qobject_cast(component.create()); + auto *party = qobject_cast(component.create()); if (party && party->host()) { qWarning() << party->host()->name() << "is having a birthday!"; diff --git a/examples/qml/referenceexamples/extended/main.cpp b/examples/qml/referenceexamples/extended/main.cpp index c99e052ae5..f91cec76b1 100644 --- a/examples/qml/referenceexamples/extended/main.cpp +++ b/examples/qml/referenceexamples/extended/main.cpp @@ -65,7 +65,7 @@ int main(int argc, char ** argv) // ![1] QQmlEngine engine; QQmlComponent component(&engine, QUrl("qrc:example.qml")); - QLineEdit *edit = qobject_cast(component.create()); + auto *edit = qobject_cast(component.create()); // ![1] if (edit) { diff --git a/examples/qml/referenceexamples/grouped/main.cpp b/examples/qml/referenceexamples/grouped/main.cpp index 17dcd09c34..14cd64fe68 100644 --- a/examples/qml/referenceexamples/grouped/main.cpp +++ b/examples/qml/referenceexamples/grouped/main.cpp @@ -66,7 +66,7 @@ int main(int argc, char ** argv) QQmlEngine engine; QQmlComponent component(&engine, QUrl("qrc:example.qml")); - BirthdayParty *party = qobject_cast(component.create()); + auto *party = qobject_cast(component.create()); if (party && party->host()) { qWarning() << party->host()->name() << "is having a birthday!"; diff --git a/examples/qml/referenceexamples/methods/birthdayparty.cpp b/examples/qml/referenceexamples/methods/birthdayparty.cpp index f13c500bcf..7e750e4f4b 100644 --- a/examples/qml/referenceexamples/methods/birthdayparty.cpp +++ b/examples/qml/referenceexamples/methods/birthdayparty.cpp @@ -82,7 +82,7 @@ Person *BirthdayParty::guest(int index) const void BirthdayParty::invite(const QString &name) { - Person *person = new Person(this); + auto *person = new Person(this); person->setName(name); m_guests.append(person); } diff --git a/examples/qml/referenceexamples/methods/main.cpp b/examples/qml/referenceexamples/methods/main.cpp index 974cc26338..89404ec822 100644 --- a/examples/qml/referenceexamples/methods/main.cpp +++ b/examples/qml/referenceexamples/methods/main.cpp @@ -63,7 +63,7 @@ int main(int argc, char ** argv) QQmlEngine engine; QQmlComponent component(&engine, QUrl("qrc:example.qml")); - BirthdayParty *party = qobject_cast(component.create()); + auto *party = qobject_cast(component.create()); if (party && party->host()) { qWarning() << party->host()->name() << "is having a birthday!"; diff --git a/examples/qml/referenceexamples/properties/main.cpp b/examples/qml/referenceexamples/properties/main.cpp index fbdbd13fd0..a0a2335034 100644 --- a/examples/qml/referenceexamples/properties/main.cpp +++ b/examples/qml/referenceexamples/properties/main.cpp @@ -65,7 +65,7 @@ int main(int argc, char ** argv) QQmlEngine engine; QQmlComponent component(&engine, QUrl("qrc:example.qml")); - BirthdayParty *party = qobject_cast(component.create()); + auto *party = qobject_cast(component.create()); if (party && party->host()) { qWarning() << party->host()->name() << "is having a birthday!"; diff --git a/examples/qml/referenceexamples/signal/main.cpp b/examples/qml/referenceexamples/signal/main.cpp index 7e096edd78..bb75e02bc2 100644 --- a/examples/qml/referenceexamples/signal/main.cpp +++ b/examples/qml/referenceexamples/signal/main.cpp @@ -67,7 +67,7 @@ int main(int argc, char ** argv) QQmlEngine engine; QQmlComponent component(&engine, QUrl("qrc:example.qml")); - BirthdayParty *party = qobject_cast(component.create()); + auto *party = qobject_cast(component.create()); if (party && party->host()) { qWarning() << party->host()->name() << "is having a birthday!"; diff --git a/examples/qml/referenceexamples/valuesource/happybirthdaysong.cpp b/examples/qml/referenceexamples/valuesource/happybirthdaysong.cpp index d8e4cad963..da09d3d7ba 100644 --- a/examples/qml/referenceexamples/valuesource/happybirthdaysong.cpp +++ b/examples/qml/referenceexamples/valuesource/happybirthdaysong.cpp @@ -54,7 +54,7 @@ HappyBirthdaySong::HappyBirthdaySong(QObject *parent) : QObject(parent), m_line(-1) { setName(QString()); - QTimer *timer = new QTimer(this); + auto *timer = new QTimer(this); QObject::connect(timer, &QTimer::timeout, this, &HappyBirthdaySong::advance); timer->start(1000); } diff --git a/examples/qml/referenceexamples/valuesource/main.cpp b/examples/qml/referenceexamples/valuesource/main.cpp index 2f3c466935..4bef695fe2 100644 --- a/examples/qml/referenceexamples/valuesource/main.cpp +++ b/examples/qml/referenceexamples/valuesource/main.cpp @@ -69,7 +69,7 @@ int main(int argc, char ** argv) QQmlEngine engine; QQmlComponent component(&engine, QUrl("qrc:example.qml")); - BirthdayParty *party = qobject_cast(component.create()); + auto *party = qobject_cast(component.create()); if (party && party->host()) { qWarning() << party->host()->name() << "is having a birthday!"; -- cgit v1.2.3 From 3cc226ffe74a45509746dddb4e72457f1651be56 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 19 Aug 2019 11:01:17 +0200 Subject: Reference Examples: Use nullptr Change-Id: I325cfdcf488e9d238e618ca23ef40aedf7c5eec1 Reviewed-by: Simon Hausmann --- examples/qml/referenceexamples/adding/person.h | 2 +- examples/qml/referenceexamples/attached/birthdayparty.h | 2 +- examples/qml/referenceexamples/attached/person.h | 6 +++--- examples/qml/referenceexamples/binding/birthdayparty.h | 2 +- examples/qml/referenceexamples/binding/happybirthdaysong.h | 2 +- examples/qml/referenceexamples/binding/person.h | 8 ++++---- examples/qml/referenceexamples/coercion/birthdayparty.h | 2 +- examples/qml/referenceexamples/coercion/person.h | 6 +++--- examples/qml/referenceexamples/default/birthdayparty.h | 2 +- examples/qml/referenceexamples/default/person.h | 6 +++--- examples/qml/referenceexamples/grouped/birthdayparty.h | 2 +- examples/qml/referenceexamples/grouped/person.h | 8 ++++---- examples/qml/referenceexamples/methods/birthdayparty.h | 2 +- examples/qml/referenceexamples/methods/person.h | 2 +- examples/qml/referenceexamples/properties/birthdayparty.h | 2 +- examples/qml/referenceexamples/properties/person.h | 2 +- examples/qml/referenceexamples/signal/birthdayparty.h | 2 +- examples/qml/referenceexamples/signal/person.h | 8 ++++---- examples/qml/referenceexamples/valuesource/birthdayparty.h | 2 +- examples/qml/referenceexamples/valuesource/happybirthdaysong.h | 2 +- examples/qml/referenceexamples/valuesource/person.h | 8 ++++---- 21 files changed, 39 insertions(+), 39 deletions(-) diff --git a/examples/qml/referenceexamples/adding/person.h b/examples/qml/referenceexamples/adding/person.h index 44e2ac3b1b..f40c8d8086 100644 --- a/examples/qml/referenceexamples/adding/person.h +++ b/examples/qml/referenceexamples/adding/person.h @@ -58,7 +58,7 @@ class Person : public QObject Q_PROPERTY(QString name READ name WRITE setName) Q_PROPERTY(int shoeSize READ shoeSize WRITE setShoeSize) public: - Person(QObject *parent = 0); + Person(QObject *parent = nullptr); QString name() const; void setName(const QString &); diff --git a/examples/qml/referenceexamples/attached/birthdayparty.h b/examples/qml/referenceexamples/attached/birthdayparty.h index 0684f16255..15375f14d9 100644 --- a/examples/qml/referenceexamples/attached/birthdayparty.h +++ b/examples/qml/referenceexamples/attached/birthdayparty.h @@ -76,7 +76,7 @@ class BirthdayParty : public QObject Q_PROPERTY(QQmlListProperty guests READ guests) Q_CLASSINFO("DefaultProperty", "guests") public: - BirthdayParty(QObject *parent = 0); + BirthdayParty(QObject *parent = nullptr); Person *host() const; void setHost(Person *); diff --git a/examples/qml/referenceexamples/attached/person.h b/examples/qml/referenceexamples/attached/person.h index 9b63773d49..2398da38bf 100644 --- a/examples/qml/referenceexamples/attached/person.h +++ b/examples/qml/referenceexamples/attached/person.h @@ -87,7 +87,7 @@ class Person : public QObject Q_PROPERTY(QString name READ name WRITE setName) Q_PROPERTY(ShoeDescription *shoe READ shoe) public: - Person(QObject *parent = 0); + Person(QObject *parent = nullptr); QString name() const; void setName(const QString &); @@ -102,14 +102,14 @@ class Boy : public Person { Q_OBJECT public: - Boy(QObject * parent = 0); + Boy(QObject * parent = nullptr); }; class Girl : public Person { Q_OBJECT public: - Girl(QObject * parent = 0); + Girl(QObject * parent = nullptr); }; #endif // PERSON_H diff --git a/examples/qml/referenceexamples/binding/birthdayparty.h b/examples/qml/referenceexamples/binding/birthdayparty.h index 93dad927d7..15e1908ece 100644 --- a/examples/qml/referenceexamples/binding/birthdayparty.h +++ b/examples/qml/referenceexamples/binding/birthdayparty.h @@ -83,7 +83,7 @@ class BirthdayParty : public QObject Q_PROPERTY(QString announcement READ announcement WRITE setAnnouncement) Q_CLASSINFO("DefaultProperty", "guests") public: - BirthdayParty(QObject *parent = 0); + BirthdayParty(QObject *parent = nullptr); Person *host() const; void setHost(Person *); diff --git a/examples/qml/referenceexamples/binding/happybirthdaysong.h b/examples/qml/referenceexamples/binding/happybirthdaysong.h index ab264b80c7..6960c7a330 100644 --- a/examples/qml/referenceexamples/binding/happybirthdaysong.h +++ b/examples/qml/referenceexamples/binding/happybirthdaysong.h @@ -61,7 +61,7 @@ class HappyBirthdaySong : public QObject, public QQmlPropertyValueSource Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) Q_INTERFACES(QQmlPropertyValueSource) public: - HappyBirthdaySong(QObject *parent = 0); + HappyBirthdaySong(QObject *parent = nullptr); virtual void setTarget(const QQmlProperty &); diff --git a/examples/qml/referenceexamples/binding/person.h b/examples/qml/referenceexamples/binding/person.h index 2cff97a6cd..543b24f971 100644 --- a/examples/qml/referenceexamples/binding/person.h +++ b/examples/qml/referenceexamples/binding/person.h @@ -61,7 +61,7 @@ class ShoeDescription : public QObject Q_PROPERTY(QString brand READ brand WRITE setBrand NOTIFY shoeChanged) Q_PROPERTY(qreal price READ price WRITE setPrice NOTIFY shoeChanged) public: - ShoeDescription(QObject *parent = 0); + ShoeDescription(QObject *parent = nullptr); int size() const; void setSize(int); @@ -92,7 +92,7 @@ class Person : public QObject Q_PROPERTY(ShoeDescription *shoe READ shoe CONSTANT) // ![0] public: - Person(QObject *parent = 0); + Person(QObject *parent = nullptr); QString name() const; void setName(const QString &); @@ -110,14 +110,14 @@ class Boy : public Person { Q_OBJECT public: - Boy(QObject * parent = 0); + Boy(QObject * parent = nullptr); }; class Girl : public Person { Q_OBJECT public: - Girl(QObject * parent = 0); + Girl(QObject * parent = nullptr); }; #endif // PERSON_H diff --git a/examples/qml/referenceexamples/coercion/birthdayparty.h b/examples/qml/referenceexamples/coercion/birthdayparty.h index bb20212ac9..554e7ab0da 100644 --- a/examples/qml/referenceexamples/coercion/birthdayparty.h +++ b/examples/qml/referenceexamples/coercion/birthdayparty.h @@ -62,7 +62,7 @@ class BirthdayParty : public QObject Q_PROPERTY(QQmlListProperty guests READ guests) // ![0] public: - BirthdayParty(QObject *parent = 0); + BirthdayParty(QObject *parent = nullptr); Person *host() const; void setHost(Person *); diff --git a/examples/qml/referenceexamples/coercion/person.h b/examples/qml/referenceexamples/coercion/person.h index 7169859cce..692cf4eb19 100644 --- a/examples/qml/referenceexamples/coercion/person.h +++ b/examples/qml/referenceexamples/coercion/person.h @@ -58,7 +58,7 @@ class Person : public QObject Q_PROPERTY(QString name READ name WRITE setName) Q_PROPERTY(int shoeSize READ shoeSize WRITE setShoeSize) public: - Person(QObject *parent = 0); + Person(QObject *parent = nullptr); QString name() const; void setName(const QString &); @@ -76,7 +76,7 @@ class Boy : public Person { Q_OBJECT public: - Boy(QObject * parent = 0); + Boy(QObject * parent = nullptr); }; //! [girl class] @@ -84,7 +84,7 @@ class Girl : public Person { Q_OBJECT public: - Girl(QObject * parent = 0); + Girl(QObject * parent = nullptr); }; //! [girl class] diff --git a/examples/qml/referenceexamples/default/birthdayparty.h b/examples/qml/referenceexamples/default/birthdayparty.h index 6acb395f47..ea63a6a16d 100644 --- a/examples/qml/referenceexamples/default/birthdayparty.h +++ b/examples/qml/referenceexamples/default/birthdayparty.h @@ -62,7 +62,7 @@ class BirthdayParty : public QObject Q_PROPERTY(QQmlListProperty guests READ guests) Q_CLASSINFO("DefaultProperty", "guests") public: - BirthdayParty(QObject *parent = 0); + BirthdayParty(QObject *parent = nullptr); Person *host() const; void setHost(Person *); diff --git a/examples/qml/referenceexamples/default/person.h b/examples/qml/referenceexamples/default/person.h index 878c2953e5..87f69276bf 100644 --- a/examples/qml/referenceexamples/default/person.h +++ b/examples/qml/referenceexamples/default/person.h @@ -58,7 +58,7 @@ class Person : public QObject Q_PROPERTY(QString name READ name WRITE setName) Q_PROPERTY(int shoeSize READ shoeSize WRITE setShoeSize) public: - Person(QObject *parent = 0); + Person(QObject *parent = nullptr); QString name() const; void setName(const QString &); @@ -74,14 +74,14 @@ class Boy : public Person { Q_OBJECT public: - Boy(QObject * parent = 0); + Boy(QObject * parent = nullptr); }; class Girl : public Person { Q_OBJECT public: - Girl(QObject * parent = 0); + Girl(QObject * parent = nullptr); }; #endif // PERSON_H diff --git a/examples/qml/referenceexamples/grouped/birthdayparty.h b/examples/qml/referenceexamples/grouped/birthdayparty.h index 7a9a03dabb..edaa11fa88 100644 --- a/examples/qml/referenceexamples/grouped/birthdayparty.h +++ b/examples/qml/referenceexamples/grouped/birthdayparty.h @@ -61,7 +61,7 @@ class BirthdayParty : public QObject Q_PROPERTY(QQmlListProperty guests READ guests) Q_CLASSINFO("DefaultProperty", "guests") public: - BirthdayParty(QObject *parent = 0); + BirthdayParty(QObject *parent = nullptr); Person *host() const; void setHost(Person *); diff --git a/examples/qml/referenceexamples/grouped/person.h b/examples/qml/referenceexamples/grouped/person.h index b4e6a894cd..6f6caaee7c 100644 --- a/examples/qml/referenceexamples/grouped/person.h +++ b/examples/qml/referenceexamples/grouped/person.h @@ -61,7 +61,7 @@ class ShoeDescription : public QObject Q_PROPERTY(QString brand READ brand WRITE setBrand) Q_PROPERTY(qreal price READ price WRITE setPrice) public: - ShoeDescription(QObject *parent = 0); + ShoeDescription(QObject *parent = nullptr); int size() const; void setSize(int); @@ -89,7 +89,7 @@ class Person : public QObject Q_PROPERTY(ShoeDescription *shoe READ shoe) // ![1] public: - Person(QObject *parent = 0); + Person(QObject *parent = nullptr); QString name() const; void setName(const QString &); @@ -104,14 +104,14 @@ class Boy : public Person { Q_OBJECT public: - Boy(QObject * parent = 0); + Boy(QObject * parent = nullptr); }; class Girl : public Person { Q_OBJECT public: - Girl(QObject * parent = 0); + Girl(QObject * parent = nullptr); }; #endif // PERSON_H diff --git a/examples/qml/referenceexamples/methods/birthdayparty.h b/examples/qml/referenceexamples/methods/birthdayparty.h index 27c164728a..0eb968a841 100644 --- a/examples/qml/referenceexamples/methods/birthdayparty.h +++ b/examples/qml/referenceexamples/methods/birthdayparty.h @@ -60,7 +60,7 @@ class BirthdayParty : public QObject Q_PROPERTY(Person *host READ host WRITE setHost) Q_PROPERTY(QQmlListProperty guests READ guests) public: - BirthdayParty(QObject *parent = 0); + BirthdayParty(QObject *parent = nullptr); Person *host() const; void setHost(Person *); diff --git a/examples/qml/referenceexamples/methods/person.h b/examples/qml/referenceexamples/methods/person.h index 488f8ebac4..749109dc72 100644 --- a/examples/qml/referenceexamples/methods/person.h +++ b/examples/qml/referenceexamples/methods/person.h @@ -58,7 +58,7 @@ class Person : public QObject Q_PROPERTY(QString name READ name WRITE setName) Q_PROPERTY(int shoeSize READ shoeSize WRITE setShoeSize) public: - Person(QObject *parent = 0); + Person(QObject *parent = nullptr); QString name() const; void setName(const QString &); diff --git a/examples/qml/referenceexamples/properties/birthdayparty.h b/examples/qml/referenceexamples/properties/birthdayparty.h index 00c5e443b4..8d62c8dcd5 100644 --- a/examples/qml/referenceexamples/properties/birthdayparty.h +++ b/examples/qml/referenceexamples/properties/birthdayparty.h @@ -68,7 +68,7 @@ class BirthdayParty : public QObject // ![2] // ![3] public: - BirthdayParty(QObject *parent = 0); + BirthdayParty(QObject *parent = nullptr); Person *host() const; void setHost(Person *); diff --git a/examples/qml/referenceexamples/properties/person.h b/examples/qml/referenceexamples/properties/person.h index 488f8ebac4..749109dc72 100644 --- a/examples/qml/referenceexamples/properties/person.h +++ b/examples/qml/referenceexamples/properties/person.h @@ -58,7 +58,7 @@ class Person : public QObject Q_PROPERTY(QString name READ name WRITE setName) Q_PROPERTY(int shoeSize READ shoeSize WRITE setShoeSize) public: - Person(QObject *parent = 0); + Person(QObject *parent = nullptr); QString name() const; void setName(const QString &); diff --git a/examples/qml/referenceexamples/signal/birthdayparty.h b/examples/qml/referenceexamples/signal/birthdayparty.h index 759450691e..9aecc8929c 100644 --- a/examples/qml/referenceexamples/signal/birthdayparty.h +++ b/examples/qml/referenceexamples/signal/birthdayparty.h @@ -76,7 +76,7 @@ class BirthdayParty : public QObject Q_PROPERTY(QQmlListProperty guests READ guests) Q_CLASSINFO("DefaultProperty", "guests") public: - BirthdayParty(QObject *parent = 0); + BirthdayParty(QObject *parent = nullptr); Person *host() const; void setHost(Person *); diff --git a/examples/qml/referenceexamples/signal/person.h b/examples/qml/referenceexamples/signal/person.h index 9b63773d49..06d4f2eb27 100644 --- a/examples/qml/referenceexamples/signal/person.h +++ b/examples/qml/referenceexamples/signal/person.h @@ -61,7 +61,7 @@ class ShoeDescription : public QObject Q_PROPERTY(QString brand READ brand WRITE setBrand) Q_PROPERTY(qreal price READ price WRITE setPrice) public: - ShoeDescription(QObject *parent = 0); + ShoeDescription(QObject *parent = nullptr); int size() const; void setSize(int); @@ -87,7 +87,7 @@ class Person : public QObject Q_PROPERTY(QString name READ name WRITE setName) Q_PROPERTY(ShoeDescription *shoe READ shoe) public: - Person(QObject *parent = 0); + Person(QObject *parent = nullptr); QString name() const; void setName(const QString &); @@ -102,14 +102,14 @@ class Boy : public Person { Q_OBJECT public: - Boy(QObject * parent = 0); + Boy(QObject * parent = nullptr); }; class Girl : public Person { Q_OBJECT public: - Girl(QObject * parent = 0); + Girl(QObject * parent = nullptr); }; #endif // PERSON_H diff --git a/examples/qml/referenceexamples/valuesource/birthdayparty.h b/examples/qml/referenceexamples/valuesource/birthdayparty.h index f965695cf6..18a9b96147 100644 --- a/examples/qml/referenceexamples/valuesource/birthdayparty.h +++ b/examples/qml/referenceexamples/valuesource/birthdayparty.h @@ -80,7 +80,7 @@ class BirthdayParty : public QObject // ![0] Q_CLASSINFO("DefaultProperty", "guests") public: - BirthdayParty(QObject *parent = 0); + BirthdayParty(QObject *parent = nullptr); Person *host() const; void setHost(Person *); diff --git a/examples/qml/referenceexamples/valuesource/happybirthdaysong.h b/examples/qml/referenceexamples/valuesource/happybirthdaysong.h index 89bd13c295..5900f118f1 100644 --- a/examples/qml/referenceexamples/valuesource/happybirthdaysong.h +++ b/examples/qml/referenceexamples/valuesource/happybirthdaysong.h @@ -65,7 +65,7 @@ class HappyBirthdaySong : public QObject, public QQmlPropertyValueSource Q_PROPERTY(QString name READ name WRITE setName) // ![1] public: - HappyBirthdaySong(QObject *parent = 0); + HappyBirthdaySong(QObject *parent = nullptr); virtual void setTarget(const QQmlProperty &); // ![1] diff --git a/examples/qml/referenceexamples/valuesource/person.h b/examples/qml/referenceexamples/valuesource/person.h index 9b63773d49..06d4f2eb27 100644 --- a/examples/qml/referenceexamples/valuesource/person.h +++ b/examples/qml/referenceexamples/valuesource/person.h @@ -61,7 +61,7 @@ class ShoeDescription : public QObject Q_PROPERTY(QString brand READ brand WRITE setBrand) Q_PROPERTY(qreal price READ price WRITE setPrice) public: - ShoeDescription(QObject *parent = 0); + ShoeDescription(QObject *parent = nullptr); int size() const; void setSize(int); @@ -87,7 +87,7 @@ class Person : public QObject Q_PROPERTY(QString name READ name WRITE setName) Q_PROPERTY(ShoeDescription *shoe READ shoe) public: - Person(QObject *parent = 0); + Person(QObject *parent = nullptr); QString name() const; void setName(const QString &); @@ -102,14 +102,14 @@ class Boy : public Person { Q_OBJECT public: - Boy(QObject * parent = 0); + Boy(QObject * parent = nullptr); }; class Girl : public Person { Q_OBJECT public: - Girl(QObject * parent = 0); + Girl(QObject * parent = nullptr); }; #endif // PERSON_H -- cgit v1.2.3 From adcb79025af8bd46a13efd4b884ff2feff64f477 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 19 Aug 2019 11:06:39 +0200 Subject: Reference Examples: Use override for overridden virtual functions Change-Id: I9f4225bf312856d08fd08431353f3cb36d0f7fa5 Reviewed-by: Fabian Kosmale Reviewed-by: Simon Hausmann --- examples/qml/referenceexamples/binding/happybirthdaysong.h | 2 +- examples/qml/referenceexamples/valuesource/happybirthdaysong.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/qml/referenceexamples/binding/happybirthdaysong.h b/examples/qml/referenceexamples/binding/happybirthdaysong.h index 6960c7a330..dcfebc06ba 100644 --- a/examples/qml/referenceexamples/binding/happybirthdaysong.h +++ b/examples/qml/referenceexamples/binding/happybirthdaysong.h @@ -63,7 +63,7 @@ class HappyBirthdaySong : public QObject, public QQmlPropertyValueSource public: HappyBirthdaySong(QObject *parent = nullptr); - virtual void setTarget(const QQmlProperty &); + void setTarget(const QQmlProperty &) override; QString name() const; void setName(const QString &); diff --git a/examples/qml/referenceexamples/valuesource/happybirthdaysong.h b/examples/qml/referenceexamples/valuesource/happybirthdaysong.h index 5900f118f1..e2205a4ebb 100644 --- a/examples/qml/referenceexamples/valuesource/happybirthdaysong.h +++ b/examples/qml/referenceexamples/valuesource/happybirthdaysong.h @@ -67,7 +67,7 @@ class HappyBirthdaySong : public QObject, public QQmlPropertyValueSource public: HappyBirthdaySong(QObject *parent = nullptr); - virtual void setTarget(const QQmlProperty &); + void setTarget(const QQmlProperty &) override; // ![1] QString name() const; -- cgit v1.2.3 From a2e10253548f1fd7f20a59e67669daa0e6713b0a Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 19 Aug 2019 11:10:51 +0200 Subject: Reference Examples: Avoid static_cast on function arguments qobject_cast is safer and not very expensive here. Change-Id: Ie87219e2a5092e453d257064a95a790de31015f5 Reviewed-by: Fabian Kosmale Reviewed-by: Simon Hausmann --- examples/qml/referenceexamples/extended/lineedit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/qml/referenceexamples/extended/lineedit.cpp b/examples/qml/referenceexamples/extended/lineedit.cpp index 777e15db07..feb1a08585 100644 --- a/examples/qml/referenceexamples/extended/lineedit.cpp +++ b/examples/qml/referenceexamples/extended/lineedit.cpp @@ -51,7 +51,7 @@ #include LineEditExtension::LineEditExtension(QObject *object) -: QObject(object), m_lineedit(static_cast(object)) +: QObject(object), m_lineedit(qobject_cast(object)) { } -- cgit v1.2.3 From 560b5bcd277907538b71c147d12fdf3d41b1848c Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 16 Aug 2019 17:14:55 +0200 Subject: examples: Fix a few linter warnings Unqualified lookup in the root object of a component is bad. Change-Id: I7772216fb81e68824519408998c73dbb1ca60c4d Reviewed-by: Fabian Kosmale Reviewed-by: Simon Hausmann --- examples/quick/shared/CheckBox.qml | 2 +- examples/quick/shared/LauncherList.qml | 11 ++++++----- examples/quick/shared/Slider.qml | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/examples/quick/shared/CheckBox.qml b/examples/quick/shared/CheckBox.qml index 7b1588d2d9..51b6aabc09 100644 --- a/examples/quick/shared/CheckBox.qml +++ b/examples/quick/shared/CheckBox.qml @@ -87,7 +87,7 @@ Item { anchors.margins: frame.width / 5 fillMode: Image.PreserveAspectFit smooth: true - visible: checked + visible: root.checked } } Text { diff --git a/examples/quick/shared/LauncherList.qml b/examples/quick/shared/LauncherList.qml index fe44cf3634..9859b5b635 100644 --- a/examples/quick/shared/LauncherList.qml +++ b/examples/quick/shared/LauncherList.qml @@ -51,6 +51,7 @@ import QtQuick 2.12 Rectangle { + id: root property int activePageCount: 0 //model is a list of {"name":"somename", "url":"file:///some/url/mainfile.qml"} @@ -74,7 +75,7 @@ Rectangle { id: launcherList clip: true delegate: SimpleLauncherDelegate{ - onClicked: showExample(url) + onClicked: root.showExample(url) } model: ListModel {id:myModel} anchors.fill: parent @@ -116,7 +117,7 @@ Rectangle { ParallelAnimation { id: showAnim ScriptAction { - script: activePageCount++ + script: root.activePageCount++ } NumberAnimation { target: launcherList @@ -144,7 +145,7 @@ Rectangle { id: exitAnim ScriptAction { - script: activePageCount-- + script: root.activePageCount-- } ParallelAnimation { @@ -182,7 +183,7 @@ Rectangle { visible: height > 0 anchors.bottom: parent.bottom width: parent.width - height: activePageCount > 0 ? 40 : 0 + height: root.activePageCount > 0 ? 40 : 0 Behavior on height { NumberAnimation { @@ -222,7 +223,7 @@ Rectangle { TapHandler { id: tapHandler - enabled: activePageCount > 0 + enabled: root.activePageCount > 0 onTapped: { pageContainer.children[pageContainer.children.length - 1].exit() } diff --git a/examples/quick/shared/Slider.qml b/examples/quick/shared/Slider.qml index cdda86e39e..5b08034571 100644 --- a/examples/quick/shared/Slider.qml +++ b/examples/quick/shared/Slider.qml @@ -83,7 +83,7 @@ Item { anchors.left: parent.left anchors.leftMargin: 16 height: childrenRect.height - width: Math.max(minLabelWidth, childrenRect.width) + width: Math.max(slider.minLabelWidth, childrenRect.width) anchors.verticalCenter: parent.verticalCenter Text { text: slider.name + ":" -- cgit v1.2.3 From 4268258b8d3ea302809c5aa5713ae9570f1739fb Mon Sep 17 00:00:00 2001 From: Sona Kurazyan Date: Fri, 2 Aug 2019 15:38:00 +0200 Subject: Remove the last usages of deprecated APIs - Replaced the usages of deprecated APIs by corresponding alternatives. - Fixed building the tests with disabled deprecated APIs. Task-number: QTBUG-76491 Change-Id: Ie8c5deb22c2074d39a64346c20e5384a7b2ad99b Reviewed-by: Volker Hilsheimer --- tests/auto/qml/qjsengine/tst_qjsengine.cpp | 7 +++ tests/auto/qml/qjsvalue/tst_qjsvalue.cpp | 59 ++++++++++++++++++++-- tests/auto/qml/qv4mm/tst_qv4mm.cpp | 2 +- .../benchmarks/qml/js/qjsengine/tst_qjsengine.cpp | 4 +- tests/benchmarks/qml/painting/paintbenchmark.cpp | 10 ++-- 5 files changed, 70 insertions(+), 12 deletions(-) diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index 0ccb8210bc..1c895eb793 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -201,7 +201,9 @@ private slots: void engineForObject(); void intConversion_QTBUG43309(); +#ifdef QT_DEPRECATED void toFixed(); +#endif void argumentEvaluationOrder(); @@ -4323,7 +4325,10 @@ void tst_QJSEngine::engineForObject() QVERIFY(!qjsEngine(&object)); QJSValue wrapper = engine.newQObject(&object); QQmlEngine::setObjectOwnership(&object, QQmlEngine::CppOwnership); + QVERIFY(qjsEngine(&object)); +#ifdef QT_DEPRECATED QCOMPARE(qjsEngine(&object), wrapper.engine()); +#endif } QVERIFY(!qjsEngine(&object)); } @@ -4338,6 +4343,7 @@ void tst_QJSEngine::intConversion_QTBUG43309() QCOMPARE(result.toNumber(), 25.0); } +#ifdef QT_DEPRECATED // QTBUG-44039 and QTBUG-43885: void tst_QJSEngine::toFixed() { @@ -4349,6 +4355,7 @@ void tst_QJSEngine::toFixed() QVERIFY(result.isString()); QCOMPARE(result.toString(), QStringLiteral("12.1")); } +#endif void tst_QJSEngine::argumentEvaluationOrder() { diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp index 4de72ae7a1..37d0ea4dea 100644 --- a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp +++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp @@ -52,7 +52,9 @@ void tst_QJSValue::ctor_invalid() { QJSValue v; QVERIFY(v.isUndefined()); +#ifdef QT_DEPRECATED QCOMPARE(v.engine(), (QJSEngine *)nullptr); +#endif } } @@ -63,7 +65,9 @@ void tst_QJSValue::ctor_undefinedWithEngine() QJSValue v = eng.toScriptValue(QVariant()); QVERIFY(v.isUndefined()); QCOMPARE(v.isObject(), false); +#ifdef QT_DEPRECATED QCOMPARE(v.engine(), &eng); +#endif } } @@ -75,7 +79,9 @@ void tst_QJSValue::ctor_nullWithEngine() QVERIFY(!v.isUndefined()); QCOMPARE(v.isNull(), true); QCOMPARE(v.isObject(), false); +#ifdef QT_DEPRECATED QCOMPARE(v.engine(), &eng); +#endif } } @@ -88,7 +94,9 @@ void tst_QJSValue::ctor_boolWithEngine() QCOMPARE(v.isBool(), true); QCOMPARE(v.isObject(), false); QCOMPARE(v.toBool(), false); +#ifdef QT_DEPRECATED QCOMPARE(v.engine(), &eng); +#endif } } @@ -101,7 +109,9 @@ void tst_QJSValue::ctor_intWithEngine() QCOMPARE(v.isNumber(), true); QCOMPARE(v.isObject(), false); QCOMPARE(v.toNumber(), 1.0); +#ifdef QT_DEPRECATED QCOMPARE(v.engine(), &eng); +#endif } } @@ -118,7 +128,9 @@ void tst_QJSValue::ctor_int() QCOMPARE(v.isNumber(), true); QCOMPARE(v.isObject(), false); QCOMPARE(v.toNumber(), 1.0); +#ifdef QT_DEPRECATED QCOMPARE(v.engine(), (QJSEngine *)nullptr); +#endif } } @@ -131,7 +143,9 @@ void tst_QJSValue::ctor_uintWithEngine() QCOMPARE(v.isNumber(), true); QCOMPARE(v.isObject(), false); QCOMPARE(v.toNumber(), 1.0); +#ifdef QT_DEPRECATED QCOMPARE(v.engine(), &eng); +#endif } } @@ -148,7 +162,9 @@ void tst_QJSValue::ctor_uint() QCOMPARE(v.isNumber(), true); QCOMPARE(v.isObject(), false); QCOMPARE(v.toNumber(), 1.0); +#ifdef QT_DEPRECATED QCOMPARE(v.engine(), (QJSEngine *)nullptr); +#endif } } @@ -161,7 +177,9 @@ void tst_QJSValue::ctor_floatWithEngine() QCOMPARE(v.isNumber(), true); QCOMPARE(v.isObject(), false); QCOMPARE(v.toNumber(), 1.0); +#ifdef QT_DEPRECATED QCOMPARE(v.engine(), &eng); +#endif } } @@ -178,7 +196,9 @@ void tst_QJSValue::ctor_float() QCOMPARE(v.isNumber(), true); QCOMPARE(v.isObject(), false); QCOMPARE(v.toNumber(), 1.0); +#ifdef QT_DEPRECATED QCOMPARE(v.engine(), (QJSEngine *)nullptr); +#endif } } @@ -191,7 +211,9 @@ void tst_QJSValue::ctor_stringWithEngine() QCOMPARE(v.isString(), true); QCOMPARE(v.isObject(), false); QCOMPARE(v.toString(), QLatin1String("ciao")); +#ifdef QT_DEPRECATED QCOMPARE(v.engine(), &eng); +#endif } } @@ -203,7 +225,9 @@ void tst_QJSValue::ctor_string() QCOMPARE(v.isString(), true); QCOMPARE(v.isObject(), false); QCOMPARE(v.toString(), QLatin1String("ciao")); +#ifdef QT_DEPRECATED QCOMPARE(v.engine(), (QJSEngine *)nullptr); +#endif } { QJSValue v("ciao"); @@ -211,7 +235,9 @@ void tst_QJSValue::ctor_string() QCOMPARE(v.isString(), true); QCOMPARE(v.isObject(), false); QCOMPARE(v.toString(), QLatin1String("ciao")); +#ifdef QT_DEPRECATED QCOMPARE(v.engine(), (QJSEngine *)nullptr); +#endif } } @@ -223,12 +249,16 @@ void tst_QJSValue::ctor_copyAndAssignWithEngine() QJSValue v = eng.toScriptValue(1.0); QJSValue v2(v); QCOMPARE(v2.strictlyEquals(v), true); +#ifdef QT_DEPRECATED QCOMPARE(v2.engine(), &eng); +#endif QJSValue v3(v); QCOMPARE(v3.strictlyEquals(v), true); QCOMPARE(v3.strictlyEquals(v2), true); +#ifdef QT_DEPRECATED QCOMPARE(v3.engine(), &eng); +#endif QJSValue v4 = eng.toScriptValue(2.0); QCOMPARE(v4.strictlyEquals(v), false); @@ -253,7 +283,9 @@ void tst_QJSValue::ctor_undefined() QJSValue v(QJSValue::UndefinedValue); QVERIFY(v.isUndefined()); QCOMPARE(v.isObject(), false); +#ifdef QT_DEPRECATED QCOMPARE(v.engine(), (QJSEngine *)nullptr); +#endif } void tst_QJSValue::ctor_null() @@ -262,7 +294,9 @@ void tst_QJSValue::ctor_null() QVERIFY(!v.isUndefined()); QCOMPARE(v.isNull(), true); QCOMPARE(v.isObject(), false); +#ifdef QT_DEPRECATED QCOMPARE(v.engine(), (QJSEngine *)nullptr); +#endif } void tst_QJSValue::ctor_bool() @@ -273,7 +307,9 @@ void tst_QJSValue::ctor_bool() QCOMPARE(v.isBool(), true); QCOMPARE(v.isObject(), false); QCOMPARE(v.toBool(), false); +#ifdef QT_DEPRECATED QCOMPARE(v.engine(), (QJSEngine *)nullptr); +#endif } void tst_QJSValue::ctor_copyAndAssign() @@ -281,12 +317,16 @@ void tst_QJSValue::ctor_copyAndAssign() QJSValue v(1.0); QJSValue v2(v); QCOMPARE(v2.strictlyEquals(v), true); +#ifdef QT_DEPRECATED QCOMPARE(v2.engine(), (QJSEngine *)nullptr); +#endif QJSValue v3(v); QCOMPARE(v3.strictlyEquals(v), true); QCOMPARE(v3.strictlyEquals(v2), true); +#ifdef QT_DEPRECATED QCOMPARE(v3.engine(), (QJSEngine *)nullptr); +#endif QJSValue v4(2.0); QCOMPARE(v4.strictlyEquals(v), false); @@ -423,7 +463,9 @@ void tst_QJSValue::toString() QCOMPARE(o.toString(), QStringLiteral("[object Object]")); o = createUnboundValue(o); +#ifdef QT_DEPRECATED QVERIFY(!o.engine()); +#endif QCOMPARE(o.toString(), QStringLiteral("[object Object]")); } @@ -435,7 +477,9 @@ void tst_QJSValue::toString() QCOMPARE(o.toString(), QStringLiteral("1,2,3")); o = createUnboundValue(o); +#ifdef QT_DEPRECATED QVERIFY(!o.engine()); +#endif QCOMPARE(o.toString(), QStringLiteral("1,2,3")); } @@ -1641,10 +1685,14 @@ void tst_QJSValue::getSetProperty() QCOMPARE(object.property("baz").toNumber(), num.toNumber()); QJSValue strstr = QJSValue("bar"); +#ifdef QT_DEPRECATED QCOMPARE(strstr.engine(), (QJSEngine *)nullptr); +#endif object.setProperty("foo", strstr); QCOMPARE(object.property("foo").toString(), strstr.toString()); +#ifdef QT_DEPRECATED QCOMPARE(strstr.engine(), &eng); // the value has been bound to the engine +#endif QJSValue numnum = QJSValue(123.0); object.setProperty("baz", numnum); @@ -2536,15 +2584,18 @@ void tst_QJSValue::engineDeleted() delete eng; QVERIFY(v1.isUndefined()); - QVERIFY(!v1.engine()); QVERIFY(v2.isUndefined()); - QVERIFY(!v2.engine()); QVERIFY(v3.isUndefined()); - QVERIFY(!v3.engine()); QVERIFY(v4.isUndefined()); - QVERIFY(!v4.engine()); QVERIFY(v5.isString()); // was not bound to engine + +#ifdef QT_DEPRECATED + QVERIFY(!v1.engine()); + QVERIFY(!v2.engine()); + QVERIFY(!v3.engine()); + QVERIFY(!v4.engine()); QVERIFY(!v5.engine()); +#endif QVERIFY(v3.property("foo").isUndefined()); } diff --git a/tests/auto/qml/qv4mm/tst_qv4mm.cpp b/tests/auto/qml/qv4mm/tst_qv4mm.cpp index 1e34b79954..5d635aa63b 100644 --- a/tests/auto/qml/qv4mm/tst_qv4mm.cpp +++ b/tests/auto/qml/qv4mm/tst_qv4mm.cpp @@ -136,7 +136,7 @@ void tst_qv4mm::clearICParent() // to change this test. for (uint i = 0; i < 16 * 1024; ++i) { QV4::Scope scope(&engine); - QV4::ScopedString s(scope, identifiers->getIndexed(i)); + QV4::ScopedString s(scope, identifiers->get(i)); QV4::Scoped ic(scope, object->internalClass()); QVERIFY(ic->d()->parent != nullptr); object->deleteProperty(s->toPropertyKey()); diff --git a/tests/benchmarks/qml/js/qjsengine/tst_qjsengine.cpp b/tests/benchmarks/qml/js/qjsengine/tst_qjsengine.cpp index d13751385c..cb23d6edbd 100644 --- a/tests/benchmarks/qml/js/qjsengine/tst_qjsengine.cpp +++ b/tests/benchmarks/qml/js/qjsengine/tst_qjsengine.cpp @@ -452,7 +452,7 @@ void tst_QJSEngine::installTranslatorFunctions() { newEngine(); QBENCHMARK { - m_engine->installTranslatorFunctions(); + m_engine->installExtensions(QJSEngine::TranslationExtension); } } @@ -471,7 +471,7 @@ void tst_QJSEngine::translation() QFETCH(QString, text); QFETCH(QString, fileName); newEngine(); - m_engine->installTranslatorFunctions(); + m_engine->installExtensions(QJSEngine::TranslationExtension); QBENCHMARK { (void)m_engine->evaluate(text, fileName); diff --git a/tests/benchmarks/qml/painting/paintbenchmark.cpp b/tests/benchmarks/qml/painting/paintbenchmark.cpp index d195675ab8..1500f39c9a 100644 --- a/tests/benchmarks/qml/painting/paintbenchmark.cpp +++ b/tests/benchmarks/qml/painting/paintbenchmark.cpp @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include @@ -328,20 +328,20 @@ public: } void paintEvent(QPaintEvent *) { - static int last = 0; + static qint64 last = 0; static bool firstRun = true; if (firstRun) { timer.start(); firstRun = false; } else { - int elapsed = timer.elapsed(); + qint64 elapsed = timer.elapsed(); qDebug() << "frame elapsed:" << elapsed - last; last = elapsed; } QPainter p(this); p.fillRect(rect(), Qt::white); p.setPen(Qt::black); - QTime drawTimer; + QElapsedTimer drawTimer; drawTimer.start(); testFunc(p); qDebug() << "draw time" << drawTimer.elapsed(); @@ -351,7 +351,7 @@ public: qApp->quit(); } - QTime timer; + QElapsedTimer timer; int frames; }; -- cgit v1.2.3 From df302c151feeb6388baaa12e79e6dc48a2942e1d Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 21 Aug 2019 09:02:59 +0200 Subject: qqmlconnections.cpp: Fix deprecation warning about QString MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit types/qqmlconnections.cpp:328:72: warning: ‘QString::QString(const char*)’ is deprecated: Use fromUtf8, QStringLiteral, or QLatin1String [-Wdeprecated-declarations] Change-Id: I3c9a341a955010a643c17e2e0a58dfdc05728e93 Reviewed-by: Fabian Kosmale Reviewed-by: Ulf Hermann --- src/qml/types/qqmlconnections.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp index 14aadb6c86..f9188b1bb5 100644 --- a/src/qml/types/qqmlconnections.cpp +++ b/src/qml/types/qqmlconnections.cpp @@ -325,7 +325,8 @@ void QQmlConnections::connectSignalsToMethods() signal->takeExpression(expression); d->boundsignals += signal; - } else if (!d->ignoreUnknownSignals && propName.startsWith("on") && propName.length() > 2 + } else if (!d->ignoreUnknownSignals + && propName.startsWith(QLatin1String("on")) && propName.length() > 2 && propName.at(2).isUpper()) { qmlWarning(this) << tr("Detected function \"%1\" in Connections element. " "This is probably intended to be a signal handler but no " -- cgit v1.2.3 From 4f9e04eaf2f8a441a374ed616bfafe8796e6ad78 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 20 Aug 2019 13:11:51 +0200 Subject: Postpone the deprecation warning for Connections onFoo until 5.15 Fixes: QTBUG-77734 Change-Id: I5c666d0aa9ec41f3d9bfcb78869b98336ede557b Reviewed-by: Fabian Kosmale Reviewed-by: Liang Qi Reviewed-by: Ulf Hermann --- src/qml/types/qqmlconnections.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp index 14aadb6c86..25f95d6c93 100644 --- a/src/qml/types/qqmlconnections.cpp +++ b/src/qml/types/qqmlconnections.cpp @@ -274,8 +274,10 @@ void QQmlConnections::connectSignals() if (d->bindings.isEmpty()) { connectSignalsToMethods(); } else { +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) qmlWarning(this) << tr("Implicitly defined onFoo properties in Connections are deprecated. " "Use this syntax instead: function onFoo() { ... }"); +#endif connectSignalsToBindings(); } } -- cgit v1.2.3 From c40d368f7328c1706ff128d2fb362f5935083c1b Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 21 Aug 2019 13:11:29 +0200 Subject: QQmlBind: Fix qdoc warning Fix src/qml/types/qqmlbind.cpp:370: (qdoc) warning: Missing '\endlist' Change-Id: I687b136caa1a1696b5efc5d8352baedfe091c89b Reviewed-by: Fabian Kosmale Reviewed-by: Ulf Hermann --- src/qml/types/qqmlbind.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp index 4b60108597..861243987f 100644 --- a/src/qml/types/qqmlbind.cpp +++ b/src/qml/types/qqmlbind.cpp @@ -357,7 +357,7 @@ void QQmlBind::setDelayed(bool delayed) \li Binding.RestoreValue The original value is restored if it was a plain value rather than a binding. \li Binding.RestoreBindingOrValue The original value is always restored. - \list + \endlist The default value is Binding.RestoreBinding. -- cgit v1.2.3 From e2b0e8dc7996013b66df3243edeb8746f12af5c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Thu, 18 Jul 2019 14:36:07 +0200 Subject: Fix deployment of QtQuick for Android with dummy_imports.qml We rely on the qmlimportscanner to find out what to deploy, but it is limited to scanning .qml files. These tests creates the QML code from C++, so qmlimportscanner fails to detect those dependencies. Therefore, we add a dummy_imports.qml file that has the sole purpose of giving qmlimportscanner which additional dependencies the test has. Change-Id: I4237b738e408c309b9b21de7e53d1a4e4acb7e2e Task-number: QTBUG-73512 Reviewed-by: Mitch Curtis --- tests/auto/qml/bindingdependencyapi/dummy_imports.qml | 8 ++++++++ tests/auto/qml/qjsengine/dummy_imports.qml | 8 ++++++++ tests/auto/qml/qmldiskcache/dummy_imports.qml | 8 ++++++++ 3 files changed, 24 insertions(+) create mode 100644 tests/auto/qml/bindingdependencyapi/dummy_imports.qml create mode 100644 tests/auto/qml/qjsengine/dummy_imports.qml create mode 100644 tests/auto/qml/qmldiskcache/dummy_imports.qml diff --git a/tests/auto/qml/bindingdependencyapi/dummy_imports.qml b/tests/auto/qml/bindingdependencyapi/dummy_imports.qml new file mode 100644 index 0000000000..b9a196e188 --- /dev/null +++ b/tests/auto/qml/bindingdependencyapi/dummy_imports.qml @@ -0,0 +1,8 @@ +// This file exists for the sole purpose for qmlimportscanner to find +// which modules it needs to extract for deployment. +// Otherwise, it fails to find the imports that are expressed in C++ +// code in tst_parserstress.cpp + +import QtQuick 2.0 + +QtObject { } // This is needed in order to keep importscanner happy diff --git a/tests/auto/qml/qjsengine/dummy_imports.qml b/tests/auto/qml/qjsengine/dummy_imports.qml new file mode 100644 index 0000000000..8d86f3583b --- /dev/null +++ b/tests/auto/qml/qjsengine/dummy_imports.qml @@ -0,0 +1,8 @@ +// This file exists for the sole purpose for qmlimportscanner to find +// which modules it needs to extract for deployment. +// Otherwise, it fails to find the imports that are expressed in C++ +// code in tst_parserstress.cpp + +import QtQml 2.0 + +QtObject { } // This is needed in order to keep importscanner happy diff --git a/tests/auto/qml/qmldiskcache/dummy_imports.qml b/tests/auto/qml/qmldiskcache/dummy_imports.qml new file mode 100644 index 0000000000..b9a196e188 --- /dev/null +++ b/tests/auto/qml/qmldiskcache/dummy_imports.qml @@ -0,0 +1,8 @@ +// This file exists for the sole purpose for qmlimportscanner to find +// which modules it needs to extract for deployment. +// Otherwise, it fails to find the imports that are expressed in C++ +// code in tst_parserstress.cpp + +import QtQuick 2.0 + +QtObject { } // This is needed in order to keep importscanner happy -- cgit v1.2.3 From c400b7765ff5204edf9243387f1928a770985382 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Mon, 19 Aug 2019 17:16:39 +0200 Subject: qqml.h: add qmlRegisterAnonymousType This version behaves for the most part like qmlRegisterType(), but it adds a uri and major version, which qmlplugindump can use to put the tpyes into the correct plugins.qmltyes file. Change-Id: I50f620216439a3edc66ac740cb051c2fbb936e51 Reviewed-by: Ulf Hermann --- src/imports/testlib/main.cpp | 2 +- src/qml/doc/src/qmlfunctions.qdoc | 10 +++++++++ src/qml/qml/qqml.h | 10 +++++++-- src/qmlmodels/qqmlmodelsmodule.cpp | 6 +++--- src/quick/items/qquickitemsmodule.cpp | 40 +++++++++++++++++------------------ src/quick/util/qquickutilmodule.cpp | 4 ++-- 6 files changed, 44 insertions(+), 28 deletions(-) diff --git a/src/imports/testlib/main.cpp b/src/imports/testlib/main.cpp index fbaf3bc4e2..33fe912692 100644 --- a/src/imports/testlib/main.cpp +++ b/src/imports/testlib/main.cpp @@ -150,7 +150,7 @@ public: qmlRegisterType(uri,1,0,"TestEvent"); qmlRegisterType(uri,1,2,"TestEvent"); qmlRegisterType(uri,1,0,"TestUtil"); - qmlRegisterType(); + qmlRegisterAnonymousType(uri); // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward qmlRegisterModule(uri, 1, QT_VERSION_MINOR); diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc index 9c106558fd..c71d18418a 100644 --- a/src/qml/doc/src/qmlfunctions.qdoc +++ b/src/qml/doc/src/qmlfunctions.qdoc @@ -273,6 +273,16 @@ {Choosing the Correct Integration Method Between C++ and QML} */ +/*! + \fn int qmlRegisterAnonymousType(const char *uri, int versionMajor) + + This template function registers the C++ type in the QML system. Instances of this type cannot be created from the QML system. + + Use this function when the type will not be referenced by name. Use \a uri and \a versionMajor to indicate to which module the type belongs. + + \sa {Choosing the Correct Integration Method Between C++ and QML} +*/ + /*! \fn int qmlRegisterType() \relates QQmlEngine diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index bfd1c88b28..a93b012c70 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -102,7 +102,7 @@ class QQmlPropertyValueInterceptor; void Q_QML_EXPORT qmlClearTypeRegistrations(); template -int qmlRegisterType() +int qmlRegisterAnonymousType(const char *uri, int versionMajor=1) { QML_GETTYPENAMES @@ -115,7 +115,7 @@ int qmlRegisterType() nullptr, QString(), - nullptr, 0, 0, nullptr, &T::staticMetaObject, + uri, versionMajor, 0, nullptr, &T::staticMetaObject, QQmlPrivate::attachedPropertiesFunc(), QQmlPrivate::attachedPropertiesMetaObject(), @@ -133,6 +133,12 @@ int qmlRegisterType() return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); } +template +QT_DEPRECATED_VERSION_X_5_14("Use qmlRegisterAnonymousType instead") int qmlRegisterType() +{ + return qmlRegisterAnonymousType(""); +} + int Q_QML_EXPORT qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message); template diff --git a/src/qmlmodels/qqmlmodelsmodule.cpp b/src/qmlmodels/qqmlmodelsmodule.cpp index 2db5dd834f..d569d8e23c 100644 --- a/src/qmlmodels/qqmlmodelsmodule.cpp +++ b/src/qmlmodels/qqmlmodelsmodule.cpp @@ -69,7 +69,7 @@ void QQmlModelsModule::registerQmlTypes() // Don't add anything here. These are only for backwards compatibility. #if QT_CONFIG(qml_object_model) qmlRegisterType("QtQml", 2, 1, "Instantiator"); // Only available in >= 2.1 - qmlRegisterType(); + qmlRegisterAnonymousType("QtQml", 2); #endif } @@ -81,7 +81,7 @@ void QQmlModelsModule::registerQuickTypes() #if QT_CONFIG(qml_object_model) qmlRegisterType(uri, 2, 1, "Instantiator"); - qmlRegisterType(); + qmlRegisterAnonymousType(uri, 2); qmlRegisterType(uri, 2, 0, "VisualItemModel"); #endif #if QT_CONFIG(qml_list_model) @@ -114,7 +114,7 @@ void QQmlModelsModule::defineModule() qmlRegisterType(uri, 2, 1, "ObjectModel"); qmlRegisterType(uri, 2, 3, "ObjectModel"); qmlRegisterType(uri, 2, 14, "Instantiator"); - qmlRegisterType(); + qmlRegisterAnonymousType(uri, 2); #endif #if QT_CONFIG(itemmodel) qmlRegisterType(uri, 2, 2, "ItemSelectionModel"); diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index 33c4fae96d..d8ad104a6d 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -247,27 +247,27 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType(uri,major,minor,"TextInput"); qmlRegisterType(uri,2,2,"TextInput"); qmlRegisterType(uri,2,4,"TextInput"); - qmlRegisterType(); + qmlRegisterAnonymousType(uri, major); #if QT_CONFIG(quick_shadereffect) - qmlRegisterType(); -#endif - qmlRegisterType(); - qmlRegisterType(); - qmlRegisterType(); - qmlRegisterType(); - qmlRegisterType(); - qmlRegisterType(); + qmlRegisterAnonymousType(uri, major); +#endif + qmlRegisterAnonymousType(uri, major); + qmlRegisterAnonymousType(uri, major); + qmlRegisterAnonymousType(uri, major); + qmlRegisterAnonymousType(uri, major); + qmlRegisterAnonymousType(uri, major); + qmlRegisterAnonymousType(uri, major); #if QT_CONFIG(quick_path) - qmlRegisterType(); - qmlRegisterType(); + qmlRegisterAnonymousType(uri, major); + qmlRegisterAnonymousType(uri, major); #endif - qmlRegisterType(); - qmlRegisterType(); - qmlRegisterType(); - qmlRegisterType(); + qmlRegisterAnonymousType(uri, major); + qmlRegisterAnonymousType(uri, major); + qmlRegisterAnonymousType(uri, major); + qmlRegisterAnonymousType(uri, major); qRegisterMetaType("QQuickAnchorLine"); - qmlRegisterType(); + qmlRegisterAnonymousType(uri, major); qmlRegisterUncreatableType(uri,major,minor,"KeyNavigation",QQuickKeyNavigationAttached::tr("KeyNavigation is only available via attached properties")); @@ -279,7 +279,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType(uri,major,minor,"PinchArea"); qmlRegisterType(uri,major,minor,"Pinch"); - qmlRegisterType(); + qmlRegisterAnonymousType(uri, major); #if QT_CONFIG(quick_shadereffect) qmlRegisterType("QtQuick", 2, 0, "ShaderEffectSource"); @@ -302,7 +302,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType(uri, major, minor,"ParentChange"); qmlRegisterType(uri, major, minor,"AnchorChanges"); - qmlRegisterType(); + qmlRegisterAnonymousType(uri, major); qmlRegisterType(uri, major, minor,"AnchorAnimation"); qmlRegisterType(uri, major, minor,"ParentAnimation"); #if QT_CONFIG(quick_path) @@ -312,8 +312,8 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) #if QT_CONFIG(quick_draganddrop) qmlRegisterType("QtQuick", 2, 0, "DropArea"); - qmlRegisterType(); - qmlRegisterType(); + qmlRegisterAnonymousType(uri, 2); + qmlRegisterAnonymousType(uri, 2); qmlRegisterUncreatableType("QtQuick", 2, 0, "Drag", QQuickDragAttached::tr("Drag is only available via attached properties")); #endif diff --git a/src/quick/util/qquickutilmodule.cpp b/src/quick/util/qquickutilmodule.cpp index d222a0c0be..7c8134ba6f 100644 --- a/src/quick/util/qquickutilmodule.cpp +++ b/src/quick/util/qquickutilmodule.cpp @@ -99,7 +99,7 @@ void QQuickUtilModule::defineModule() qmlRegisterType("QtQuick",2,0,"Vector3dAnimation"); #if QT_CONFIG(validator) - qmlRegisterType(); + qmlRegisterAnonymousType("QtQuick", 2); qmlRegisterType("QtQuick",2,0,"IntValidator"); qmlRegisterType("QtQuick",2,0,"DoubleValidator"); qmlRegisterType("QtQuick",2,0,"RegExpValidator"); @@ -117,7 +117,7 @@ void QQuickUtilModule::defineModule() #if QT_CONFIG(quick_shadereffect) && QT_CONFIG(opengl) qmlRegisterType("QtQuick", 2, 2, "UniformAnimator"); #endif - qmlRegisterType(); + qmlRegisterAnonymousType("QtQuick", 2); qmlRegisterCustomType("QtQuick",2,0,"PropertyChanges", new QQuickPropertyChangesParser); -- cgit v1.2.3 From 720dd939b4ee9571d847465c83b6431a7bdf0d7e Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Sat, 10 Aug 2019 18:07:07 +0200 Subject: Make ImageParticle functional when rendering via the RHI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Involves a trivial (albeit time consuming) rework of the existing materials as well since their reliance on QSGSimpleMaterial makes them problematic to live side-by-side with the RHI variants. Change-Id: Ie12b7949904434b3a831588518c8268e917ce92f Reviewed-by: Christian Strømme --- src/particles/particles.qrc | 11 + src/particles/qquickimageparticle.cpp | 735 +++++++++++++++++---- src/particles/qquickimageparticle_p.h | 29 +- src/particles/qquickparticlepainter.cpp | 2 + src/particles/qquickparticlepainter_p.h | 1 + src/particles/shaders_ng/compile.bat | 53 ++ src/particles/shaders_ng/imageparticle.frag | 55 ++ src/particles/shaders_ng/imageparticle.vert | 145 ++++ .../shaders_ng/imageparticle_colored.frag.qsb | Bin 0 -> 1990 bytes .../shaders_ng/imageparticle_colored.vert.qsb | Bin 0 -> 3677 bytes .../shaders_ng/imageparticle_deformed.frag.qsb | Bin 0 -> 2028 bytes .../shaders_ng/imageparticle_deformed.vert.qsb | Bin 0 -> 5044 bytes .../shaders_ng/imageparticle_simple.frag.qsb | Bin 0 -> 2000 bytes .../shaders_ng/imageparticle_simple.vert.qsb | Bin 0 -> 3639 bytes .../shaders_ng/imageparticle_sprite.frag.qsb | Bin 0 -> 2369 bytes .../shaders_ng/imageparticle_sprite.vert.qsb | Bin 0 -> 5964 bytes .../shaders_ng/imageparticle_tabled.frag.qsb | Bin 0 -> 2240 bytes .../shaders_ng/imageparticle_tabled.vert.qsb | Bin 0 -> 5462 bytes 18 files changed, 884 insertions(+), 147 deletions(-) create mode 100755 src/particles/shaders_ng/compile.bat create mode 100644 src/particles/shaders_ng/imageparticle.frag create mode 100644 src/particles/shaders_ng/imageparticle.vert create mode 100644 src/particles/shaders_ng/imageparticle_colored.frag.qsb create mode 100644 src/particles/shaders_ng/imageparticle_colored.vert.qsb create mode 100644 src/particles/shaders_ng/imageparticle_deformed.frag.qsb create mode 100644 src/particles/shaders_ng/imageparticle_deformed.vert.qsb create mode 100644 src/particles/shaders_ng/imageparticle_simple.frag.qsb create mode 100644 src/particles/shaders_ng/imageparticle_simple.vert.qsb create mode 100644 src/particles/shaders_ng/imageparticle_sprite.frag.qsb create mode 100644 src/particles/shaders_ng/imageparticle_sprite.vert.qsb create mode 100644 src/particles/shaders_ng/imageparticle_tabled.frag.qsb create mode 100644 src/particles/shaders_ng/imageparticle_tabled.vert.qsb diff --git a/src/particles/particles.qrc b/src/particles/particles.qrc index ad44cf406e..c7102b9aa5 100644 --- a/src/particles/particles.qrc +++ b/src/particles/particles.qrc @@ -16,5 +16,16 @@ shaders/customparticletemplate_core.vert shaders/imageparticle_core.frag shaders/imageparticle_core.vert + + shaders_ng/imageparticle_simple.vert.qsb + shaders_ng/imageparticle_simple.frag.qsb + shaders_ng/imageparticle_tabled.vert.qsb + shaders_ng/imageparticle_tabled.frag.qsb + shaders_ng/imageparticle_deformed.vert.qsb + shaders_ng/imageparticle_deformed.frag.qsb + shaders_ng/imageparticle_sprite.vert.qsb + shaders_ng/imageparticle_sprite.frag.qsb + shaders_ng/imageparticle_colored.vert.qsb + shaders_ng/imageparticle_colored.frag.qsb diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp index ae1ef80026..649fbb30c2 100644 --- a/src/particles/qquickimageparticle.cpp +++ b/src/particles/qquickimageparticle.cpp @@ -1,6 +1,6 @@ -/**************************************************************************** +/**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQuick module of the Qt Toolkit. @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include @@ -56,13 +55,15 @@ #include #include #include +#include QT_BEGIN_NAMESPACE -//TODO: Make it larger on desktop? Requires fixing up shader code with the same define +// Must match the shader code #define UNIFORM_ARRAY_SIZE 64 const qreal CONV = 0.017453292519943295; + class ImageMaterialData { public: @@ -85,13 +86,10 @@ class ImageMaterialData QSizeF animSheetSize; }; -class TabledMaterialData : public ImageMaterialData {}; -class TabledMaterial : public QSGSimpleMaterialShader +class TabledMaterialShader : public QSGMaterialShader { - QSG_DECLARE_SIMPLE_SHADER(TabledMaterial, TabledMaterialData) - public: - TabledMaterial() + TabledMaterialShader() { QSGShaderSourceBuilder builder; const bool isES = QOpenGLContext::currentContext()->isOpenGLES(); @@ -122,36 +120,47 @@ public: const char *vertexShader() const override { return m_vertex_code.constData(); } const char *fragmentShader() const override { return m_fragment_code.constData(); } - QList attributes() const override { - return QList() << "vPosTex" << "vData" << "vVec" - << "vColor" << "vDeformVec" << "vRotation"; - }; + char const *const *attributeNames() const override + { + static const char *const attr[] = { "vPosTex", "vData", "vVec", "vColor", "vDeformVec", "vRotation", nullptr }; + return attr; + } void initialize() override { - QSGSimpleMaterialShader::initialize(); program()->bind(); program()->setUniformValue("_qt_texture", 0); program()->setUniformValue("colortable", 1); glFuncs = QOpenGLContext::currentContext()->functions(); + m_matrix_id = program()->uniformLocation("qt_Matrix"); + m_opacity_id = program()->uniformLocation("qt_Opacity"); m_timestamp_id = program()->uniformLocation("timestamp"); m_entry_id = program()->uniformLocation("entry"); m_sizetable_id = program()->uniformLocation("sizetable"); m_opacitytable_id = program()->uniformLocation("opacitytable"); } - void updateState(const TabledMaterialData* d, const TabledMaterialData*) override { + void updateState(const RenderState &renderState, QSGMaterial *mat, QSGMaterial *) override { + ImageMaterialData *state = static_cast(mat)->state(); + + if (renderState.isMatrixDirty()) + program()->setUniformValue(m_matrix_id, renderState.combinedMatrix()); + if (renderState.isOpacityDirty() && m_opacity_id >= 0) + program()->setUniformValue(m_opacity_id, renderState.opacity()); + glFuncs->glActiveTexture(GL_TEXTURE1); - d->colorTable->bind(); + state->colorTable->bind(); glFuncs->glActiveTexture(GL_TEXTURE0); - d->texture->bind(); + state->texture->bind(); - program()->setUniformValue(m_timestamp_id, (float) d->timestamp); - program()->setUniformValue(m_entry_id, (float) d->entry); - program()->setUniformValueArray(m_sizetable_id, (const float*) d->sizeTable, UNIFORM_ARRAY_SIZE, 1); - program()->setUniformValueArray(m_opacitytable_id, (const float*) d->opacityTable, UNIFORM_ARRAY_SIZE, 1); + program()->setUniformValue(m_timestamp_id, (float) state->timestamp); + program()->setUniformValue(m_entry_id, (float) state->entry); + program()->setUniformValueArray(m_sizetable_id, (const float*) state->sizeTable, UNIFORM_ARRAY_SIZE, 1); + program()->setUniformValueArray(m_opacitytable_id, (const float*) state->opacityTable, UNIFORM_ARRAY_SIZE, 1); } + int m_matrix_id; + int m_opacity_id; int m_entry_id; int m_timestamp_id; int m_sizetable_id; @@ -161,13 +170,91 @@ public: QOpenGLFunctions* glFuncs; }; -class DeformableMaterialData : public ImageMaterialData {}; -class DeformableMaterial : public QSGSimpleMaterialShader +class TabledMaterialRhiShader : public QSGMaterialRhiShader +{ +public: + TabledMaterialRhiShader() + { + setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_tabled.vert.qsb")); + setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_tabled.frag.qsb")); + } + + bool updateUniformData(const RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override + { + QByteArray *buf = renderState.uniformData(); + Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4)); + + if (renderState.isMatrixDirty()) { + const QMatrix4x4 m = renderState.combinedMatrix(); + memcpy(buf->data(), m.constData(), 64); + } + + if (renderState.isOpacityDirty()) { + const float opacity = renderState.opacity(); + memcpy(buf->data() + 64, &opacity, 4); + } + + ImageMaterialData *state = static_cast(newMaterial)->state(); + + float entry = float(state->entry); + memcpy(buf->data() + 68, &entry, 4); + + float timestamp = float(state->timestamp); + memcpy(buf->data() + 72, ×tamp, 4); + + float *p = reinterpret_cast(buf->data() + 80); + for (int i = 0; i < UNIFORM_ARRAY_SIZE; ++i) { + *p = state->sizeTable[i]; + p += 4; + } + p = reinterpret_cast(buf->data() + 80 + (UNIFORM_ARRAY_SIZE * 4 * 4)); + for (int i = 0; i < UNIFORM_ARRAY_SIZE; ++i) { + *p = state->opacityTable[i]; + p += 4; + } + + return true; + } + + void updateSampledImage(const RenderState &renderState, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *) override + { + ImageMaterialData *state = static_cast(newMaterial)->state(); + if (binding == 2) { + state->colorTable->updateRhiTexture(renderState.rhi(), renderState.resourceUpdateBatch()); + *texture = state->colorTable; + } else if (binding == 1) { + state->texture->updateRhiTexture(renderState.rhi(), renderState.resourceUpdateBatch()); + *texture = state->texture; + } + } +}; + +class TabledMaterial : public ImageMaterial { - QSG_DECLARE_SIMPLE_SHADER(DeformableMaterial, DeformableMaterialData) +public: + TabledMaterial() { setFlag(SupportsRhiShader, true); } + QSGMaterialShader *createShader() const override { + if (flags().testFlag(RhiShaderWanted)) + return new TabledMaterialRhiShader; + else + return new TabledMaterialShader; + } + QSGMaterialType *type() const override { return &m_type; } + + ImageMaterialData *state() override { return &m_state; } +private: + static QSGMaterialType m_type; + ImageMaterialData m_state; +}; + +QSGMaterialType TabledMaterial::m_type; + +class DeformableMaterialShader : public QSGMaterialShader +{ public: - DeformableMaterial() + DeformableMaterialShader() { QSGShaderSourceBuilder builder; const bool isES = QOpenGLContext::currentContext()->isOpenGLES(); @@ -196,27 +283,38 @@ public: const char *vertexShader() const override { return m_vertex_code.constData(); } const char *fragmentShader() const override { return m_fragment_code.constData(); } - QList attributes() const override { - return QList() << "vPosTex" << "vData" << "vVec" - << "vColor" << "vDeformVec" << "vRotation"; - }; + char const *const *attributeNames() const override + { + static const char *const attr[] = { "vPosTex", "vData", "vVec", "vColor", "vDeformVec", "vRotation", nullptr }; + return attr; + } void initialize() override { - QSGSimpleMaterialShader::initialize(); program()->bind(); program()->setUniformValue("_qt_texture", 0); glFuncs = QOpenGLContext::currentContext()->functions(); + m_matrix_id = program()->uniformLocation("qt_Matrix"); + m_opacity_id = program()->uniformLocation("qt_Opacity"); m_timestamp_id = program()->uniformLocation("timestamp"); m_entry_id = program()->uniformLocation("entry"); } - void updateState(const DeformableMaterialData* d, const DeformableMaterialData*) override { - d->texture->bind(); + void updateState(const RenderState &renderState, QSGMaterial *mat, QSGMaterial *) override { + ImageMaterialData *state = static_cast(mat)->state(); + + if (renderState.isMatrixDirty()) + program()->setUniformValue(m_matrix_id, renderState.combinedMatrix()); + if (renderState.isOpacityDirty() && m_opacity_id >= 0) + program()->setUniformValue(m_opacity_id, renderState.opacity()); + + state->texture->bind(); - program()->setUniformValue(m_timestamp_id, (float) d->timestamp); - program()->setUniformValue(m_entry_id, (float) d->entry); + program()->setUniformValue(m_timestamp_id, (float) state->timestamp); + program()->setUniformValue(m_entry_id, (float) state->entry); } + int m_matrix_id; + int m_opacity_id; int m_entry_id; int m_timestamp_id; QByteArray m_vertex_code; @@ -224,13 +322,77 @@ public: QOpenGLFunctions* glFuncs; }; -class SpriteMaterialData : public ImageMaterialData {}; -class SpriteMaterial : public QSGSimpleMaterialShader +class DeformableMaterialRhiShader : public QSGMaterialRhiShader { - QSG_DECLARE_SIMPLE_SHADER(SpriteMaterial, SpriteMaterialData) +public: + DeformableMaterialRhiShader() + { + setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_deformed.vert.qsb")); + setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_deformed.frag.qsb")); + } + bool updateUniformData(const RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override + { + QByteArray *buf = renderState.uniformData(); + Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4)); + + if (renderState.isMatrixDirty()) { + const QMatrix4x4 m = renderState.combinedMatrix(); + memcpy(buf->data(), m.constData(), 64); + } + + if (renderState.isOpacityDirty()) { + const float opacity = renderState.opacity(); + memcpy(buf->data() + 64, &opacity, 4); + } + + ImageMaterialData *state = static_cast(newMaterial)->state(); + + float entry = float(state->entry); + memcpy(buf->data() + 68, &entry, 4); + + float timestamp = float(state->timestamp); + memcpy(buf->data() + 72, ×tamp, 4); + + return true; + } + + void updateSampledImage(const RenderState &renderState, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *) override + { + ImageMaterialData *state = static_cast(newMaterial)->state(); + if (binding == 1) { + state->texture->updateRhiTexture(renderState.rhi(), renderState.resourceUpdateBatch()); + *texture = state->texture; + } + } +}; + +class DeformableMaterial : public ImageMaterial +{ public: - SpriteMaterial() + DeformableMaterial() { setFlag(SupportsRhiShader, true); } + QSGMaterialShader *createShader() const override { + if (flags().testFlag(RhiShaderWanted)) + return new DeformableMaterialRhiShader; + else + return new DeformableMaterialShader; + } + QSGMaterialType *type() const override { return &m_type; } + + ImageMaterialData *state() override { return &m_state; } + +private: + static QSGMaterialType m_type; + ImageMaterialData m_state; +}; + +QSGMaterialType DeformableMaterial::m_type; + +class SpriteMaterialShader : public QSGMaterialShader +{ +public: + SpriteMaterialShader() { QSGShaderSourceBuilder builder; const bool isES = QOpenGLContext::currentContext()->isOpenGLES(); @@ -263,17 +425,20 @@ public: const char *vertexShader() const override { return m_vertex_code.constData(); } const char *fragmentShader() const override { return m_fragment_code.constData(); } - QList attributes() const override { - return QList() << "vPosTex" << "vData" << "vVec" - << "vColor" << "vDeformVec" << "vRotation" << "vAnimData" << "vAnimPos"; + char const *const *attributeNames() const override + { + static const char *const attr[] = { "vPosTex", "vData", "vVec", "vColor", "vDeformVec", "vRotation", + "vAnimData", "vAnimPos", nullptr }; + return attr; } void initialize() override { - QSGSimpleMaterialShader::initialize(); program()->bind(); program()->setUniformValue("_qt_texture", 0); program()->setUniformValue("colortable", 1); glFuncs = QOpenGLContext::currentContext()->functions(); + m_matrix_id = program()->uniformLocation("qt_Matrix"); + m_opacity_id = program()->uniformLocation("qt_Opacity"); //Don't actually expose the animSheetSize in the shader, it's currently only used for CPU calculations. m_timestamp_id = program()->uniformLocation("timestamp"); m_entry_id = program()->uniformLocation("entry"); @@ -281,20 +446,29 @@ public: m_opacitytable_id = program()->uniformLocation("opacitytable"); } - void updateState(const SpriteMaterialData* d, const SpriteMaterialData*) override { + void updateState(const RenderState &renderState, QSGMaterial *mat, QSGMaterial *) override { + ImageMaterialData *state = static_cast(mat)->state(); + + if (renderState.isMatrixDirty()) + program()->setUniformValue(m_matrix_id, renderState.combinedMatrix()); + if (renderState.isOpacityDirty() && m_opacity_id >= 0) + program()->setUniformValue(m_opacity_id, renderState.opacity()); + glFuncs->glActiveTexture(GL_TEXTURE1); - d->colorTable->bind(); + state->colorTable->bind(); // make sure we end by setting GL_TEXTURE0 as active texture glFuncs->glActiveTexture(GL_TEXTURE0); - d->texture->bind(); + state->texture->bind(); - program()->setUniformValue(m_timestamp_id, (float) d->timestamp); - program()->setUniformValue(m_entry_id, (float) d->entry); - program()->setUniformValueArray(m_sizetable_id, (const float*) d->sizeTable, 64, 1); - program()->setUniformValueArray(m_opacitytable_id, (const float*) d->opacityTable, UNIFORM_ARRAY_SIZE, 1); + program()->setUniformValue(m_timestamp_id, (float) state->timestamp); + program()->setUniformValue(m_entry_id, (float) state->entry); + program()->setUniformValueArray(m_sizetable_id, (const float*) state->sizeTable, 64, 1); + program()->setUniformValueArray(m_opacitytable_id, (const float*) state->opacityTable, UNIFORM_ARRAY_SIZE, 1); } + int m_matrix_id; + int m_opacity_id; int m_timestamp_id; int m_entry_id; int m_sizetable_id; @@ -304,13 +478,91 @@ public: QOpenGLFunctions* glFuncs; }; -class ColoredMaterialData : public ImageMaterialData {}; -class ColoredMaterial : public QSGSimpleMaterialShader +class SpriteMaterialRhiShader : public QSGMaterialRhiShader { - QSG_DECLARE_SIMPLE_SHADER(ColoredMaterial, ColoredMaterialData) +public: + SpriteMaterialRhiShader() + { + setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_sprite.vert.qsb")); + setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_sprite.frag.qsb")); + } + + bool updateUniformData(const RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override + { + QByteArray *buf = renderState.uniformData(); + Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4)); + + if (renderState.isMatrixDirty()) { + const QMatrix4x4 m = renderState.combinedMatrix(); + memcpy(buf->data(), m.constData(), 64); + } + + if (renderState.isOpacityDirty()) { + const float opacity = renderState.opacity(); + memcpy(buf->data() + 64, &opacity, 4); + } + ImageMaterialData *state = static_cast(newMaterial)->state(); + + float entry = float(state->entry); + memcpy(buf->data() + 68, &entry, 4); + + float timestamp = float(state->timestamp); + memcpy(buf->data() + 72, ×tamp, 4); + + float *p = reinterpret_cast(buf->data() + 80); + for (int i = 0; i < UNIFORM_ARRAY_SIZE; ++i) { + *p = state->sizeTable[i]; + p += 4; + } + p = reinterpret_cast(buf->data() + 80 + (UNIFORM_ARRAY_SIZE * 4 * 4)); + for (int i = 0; i < UNIFORM_ARRAY_SIZE; ++i) { + *p = state->opacityTable[i]; + p += 4; + } + + return true; + } + + void updateSampledImage(const RenderState &renderState, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *) override + { + ImageMaterialData *state = static_cast(newMaterial)->state(); + if (binding == 2) { + state->colorTable->updateRhiTexture(renderState.rhi(), renderState.resourceUpdateBatch()); + *texture = state->colorTable; + } else if (binding == 1) { + state->texture->updateRhiTexture(renderState.rhi(), renderState.resourceUpdateBatch()); + *texture = state->texture; + } + } +}; + +class SpriteMaterial : public ImageMaterial +{ public: - ColoredMaterial() + SpriteMaterial() { setFlag(SupportsRhiShader, true); } + QSGMaterialShader *createShader() const override { + if (flags().testFlag(RhiShaderWanted)) + return new SpriteMaterialRhiShader; + else + return new SpriteMaterialShader; + } + QSGMaterialType *type() const override { return &m_type; } + + ImageMaterialData *state() override { return &m_state; } + +private: + static QSGMaterialType m_type; + ImageMaterialData m_state; +}; + +QSGMaterialType SpriteMaterial::m_type; + +class ColoredMaterialShader : public QSGMaterialShader +{ +public: + ColoredMaterialShader() { QSGShaderSourceBuilder builder; const bool isES = QOpenGLContext::currentContext()->isOpenGLES(); @@ -337,8 +589,23 @@ public: const char *vertexShader() const override { return m_vertex_code.constData(); } const char *fragmentShader() const override { return m_fragment_code.constData(); } + char const *const *attributeNames() const override + { + static const char *const attr[] = { "vPos", "vData", "vVec", "vColor", nullptr }; + return attr; + } + + void initialize() override { + program()->bind(); + program()->setUniformValue("_qt_texture", 0); + glFuncs = QOpenGLContext::currentContext()->functions(); + m_matrix_id = program()->uniformLocation("qt_Matrix"); + m_opacity_id = program()->uniformLocation("qt_Opacity"); + m_timestamp_id = program()->uniformLocation("timestamp"); + m_entry_id = program()->uniformLocation("entry"); + } + void activate() override { - QSGSimpleMaterialShader::activate(); #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN) glEnable(GL_POINT_SPRITE); glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); @@ -346,33 +613,28 @@ public: } void deactivate() override { - QSGSimpleMaterialShader::deactivate(); #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN) glDisable(GL_POINT_SPRITE); glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); #endif } - QList attributes() const override { - return QList() << "vPos" << "vData" << "vVec" << "vColor"; - } + void updateState(const RenderState &renderState, QSGMaterial *mat, QSGMaterial *) override { + ImageMaterialData *state = static_cast(mat)->state(); - void initialize() override { - QSGSimpleMaterialShader::initialize(); - program()->bind(); - program()->setUniformValue("_qt_texture", 0); - glFuncs = QOpenGLContext::currentContext()->functions(); - m_timestamp_id = program()->uniformLocation("timestamp"); - m_entry_id = program()->uniformLocation("entry"); - } + if (renderState.isMatrixDirty()) + program()->setUniformValue(m_matrix_id, renderState.combinedMatrix()); + if (renderState.isOpacityDirty() && m_opacity_id >= 0) + program()->setUniformValue(m_opacity_id, renderState.opacity()); - void updateState(const ColoredMaterialData* d, const ColoredMaterialData*) override { - d->texture->bind(); + state->texture->bind(); - program()->setUniformValue(m_timestamp_id, (float) d->timestamp); - program()->setUniformValue(m_entry_id, (float) d->entry); + program()->setUniformValue(m_timestamp_id, (float) state->timestamp); + program()->setUniformValue(m_entry_id, (float) state->entry); } + int m_matrix_id; + int m_opacity_id; int m_timestamp_id; int m_entry_id; QByteArray m_vertex_code; @@ -380,13 +642,77 @@ public: QOpenGLFunctions* glFuncs; }; -class SimpleMaterialData : public ImageMaterialData {}; -class SimpleMaterial : public QSGSimpleMaterialShader +class ColoredMaterialRhiShader : public QSGMaterialRhiShader +{ +public: + ColoredMaterialRhiShader() + { + setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_colored.vert.qsb")); + setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_colored.frag.qsb")); + } + + bool updateUniformData(const RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override + { + QByteArray *buf = renderState.uniformData(); + Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4)); + + if (renderState.isMatrixDirty()) { + const QMatrix4x4 m = renderState.combinedMatrix(); + memcpy(buf->data(), m.constData(), 64); + } + + if (renderState.isOpacityDirty()) { + const float opacity = renderState.opacity(); + memcpy(buf->data() + 64, &opacity, 4); + } + + ImageMaterialData *state = static_cast(newMaterial)->state(); + + float entry = float(state->entry); + memcpy(buf->data() + 68, &entry, 4); + + float timestamp = float(state->timestamp); + memcpy(buf->data() + 72, ×tamp, 4); + + return true; + } + + void updateSampledImage(const RenderState &renderState, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *) override + { + ImageMaterialData *state = static_cast(newMaterial)->state(); + if (binding == 1) { + state->texture->updateRhiTexture(renderState.rhi(), renderState.resourceUpdateBatch()); + *texture = state->texture; + } + } +}; + +class ColoredMaterial : public ImageMaterial { - QSG_DECLARE_SIMPLE_SHADER(SimpleMaterial, SimpleMaterialData) +public: + ColoredMaterial() { setFlag(SupportsRhiShader, true); } + QSGMaterialShader *createShader() const override { + if (flags().testFlag(RhiShaderWanted)) + return new ColoredMaterialRhiShader; + else + return new ColoredMaterialShader; + } + QSGMaterialType *type() const override { return &m_type; } + ImageMaterialData *state() override { return &m_state; } + +private: + static QSGMaterialType m_type; + ImageMaterialData m_state; +}; + +QSGMaterialType ColoredMaterial::m_type; + +class SimpleMaterialShader : public QSGMaterialShader +{ public: - SimpleMaterial() + SimpleMaterialShader() { QSGShaderSourceBuilder builder; const bool isES = QOpenGLContext::currentContext()->isOpenGLES(); @@ -411,8 +737,23 @@ public: const char *vertexShader() const override { return m_vertex_code.constData(); } const char *fragmentShader() const override { return m_fragment_code.constData(); } + char const *const *attributeNames() const override + { + static const char *const attr[] = { "vPos", "vData", "vVec", nullptr }; + return attr; + } + + void initialize() override { + program()->bind(); + program()->setUniformValue("_qt_texture", 0); + glFuncs = QOpenGLContext::currentContext()->functions(); + m_matrix_id = program()->uniformLocation("qt_Matrix"); + m_opacity_id = program()->uniformLocation("qt_Opacity"); + m_timestamp_id = program()->uniformLocation("timestamp"); + m_entry_id = program()->uniformLocation("entry"); + } + void activate() override { - QSGSimpleMaterialShader::activate(); #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN) glEnable(GL_POINT_SPRITE); glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); @@ -420,33 +761,28 @@ public: } void deactivate() override { - QSGSimpleMaterialShader::deactivate(); #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN) glDisable(GL_POINT_SPRITE); glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); #endif } - QList attributes() const override { - return QList() << "vPos" << "vData" << "vVec"; - } + void updateState(const RenderState &renderState, QSGMaterial *mat, QSGMaterial *) override { + ImageMaterialData *state = static_cast(mat)->state(); - void initialize() override { - QSGSimpleMaterialShader::initialize(); - program()->bind(); - program()->setUniformValue("_qt_texture", 0); - glFuncs = QOpenGLContext::currentContext()->functions(); - m_timestamp_id = program()->uniformLocation("timestamp"); - m_entry_id = program()->uniformLocation("entry"); - } + if (renderState.isMatrixDirty()) + program()->setUniformValue(m_matrix_id, renderState.combinedMatrix()); + if (renderState.isOpacityDirty() && m_opacity_id >= 0) + program()->setUniformValue(m_opacity_id, renderState.opacity()); - void updateState(const SimpleMaterialData* d, const SimpleMaterialData*) override { - d->texture->bind(); + state->texture->bind(); - program()->setUniformValue(m_timestamp_id, (float) d->timestamp); - program()->setUniformValue(m_entry_id, (float) d->entry); + program()->setUniformValue(m_timestamp_id, (float) state->timestamp); + program()->setUniformValue(m_entry_id, (float) state->entry); } + int m_matrix_id; + int m_opacity_id; int m_timestamp_id; int m_entry_id; QByteArray m_vertex_code; @@ -454,6 +790,73 @@ public: QOpenGLFunctions* glFuncs; }; +class SimpleMaterialRhiShader : public QSGMaterialRhiShader +{ +public: + SimpleMaterialRhiShader() + { + setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_simple.vert.qsb")); + setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_simple.frag.qsb")); + } + + bool updateUniformData(const RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override + { + QByteArray *buf = renderState.uniformData(); + Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4)); + + if (renderState.isMatrixDirty()) { + const QMatrix4x4 m = renderState.combinedMatrix(); + memcpy(buf->data(), m.constData(), 64); + } + + if (renderState.isOpacityDirty()) { + const float opacity = renderState.opacity(); + memcpy(buf->data() + 64, &opacity, 4); + } + + ImageMaterialData *state = static_cast(newMaterial)->state(); + + float entry = float(state->entry); + memcpy(buf->data() + 68, &entry, 4); + + float timestamp = float(state->timestamp); + memcpy(buf->data() + 72, ×tamp, 4); + + return true; + } + + void updateSampledImage(const RenderState &renderState, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *) override + { + ImageMaterialData *state = static_cast(newMaterial)->state(); + if (binding == 1) { + state->texture->updateRhiTexture(renderState.rhi(), renderState.resourceUpdateBatch()); + *texture = state->texture; + } + } +}; + +class SimpleMaterial : public ImageMaterial +{ +public: + SimpleMaterial() { setFlag(SupportsRhiShader, true); } + QSGMaterialShader *createShader() const override { + if (flags().testFlag(RhiShaderWanted)) + return new SimpleMaterialRhiShader; + else + return new SimpleMaterialShader; + } + QSGMaterialType *type() const override { return &m_type; } + + ImageMaterialData *state() override { return &m_state; } + +private: + static QSGMaterialType m_type; + ImageMaterialData m_state; +}; + +QSGMaterialType SimpleMaterial::m_type; + void fillUniformArrayFromImage(float* array, const QImage& img, int size) { if (img.isNull()){ @@ -726,6 +1129,8 @@ QQuickImageParticle::QQuickImageParticle(QQuickItem* parent) , m_debugMode(false) , m_entryEffect(Fade) , m_startedImageLoading(0) + , m_rhi(nullptr) + , m_apiChecked(false) { setFlag(ItemHasContents); } @@ -1000,7 +1405,7 @@ void QQuickImageParticle::setEntryEffect(EntryEffect arg) if (m_entryEffect != arg) { m_entryEffect = arg; if (m_material) - getState(m_material)->entry = (qreal) m_entryEffect; + getState(m_material)->entry = (qreal) m_entryEffect; emit entryEffectChanged(arg); } } @@ -1224,7 +1629,7 @@ void QQuickImageParticle::buildParticleNodes(QSGNode** passThrough) void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) { - if (!QOpenGLContext::currentContext()) + if (!m_rhi && !QOpenGLContext::currentContext()) return; if (m_count * 4 > 0xffff) { @@ -1271,28 +1676,38 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) } } } + + if (!m_rhi) { // the RHI may be backed by GL but these checks should be obsolete in any case #ifdef Q_OS_WIN - if (perfLevel < Deformable) //QTBUG-24540 , point sprite 'extension' isn't working on windows. - perfLevel = Deformable; + if (perfLevel < Deformable) //QTBUG-24540 , point sprite 'extension' isn't working on windows. + perfLevel = Deformable; #endif #ifdef Q_OS_MAC - // OS X 10.8.3 introduced a bug in the AMD drivers, for at least the 2011 macbook pros, - // causing point sprites who read gl_PointCoord in the frag shader to come out as - // green-red blobs. - const GLubyte *glVendor = QOpenGLContext::currentContext()->functions()->glGetString(GL_VENDOR); - if (perfLevel < Deformable && glVendor && strstr((char *) glVendor, "ATI")) { - perfLevel = Deformable; - } + // macOS 10.8.3 introduced a bug in the AMD drivers, for at least the 2011 macbook pros, + // causing point sprites who read gl_PointCoord in the frag shader to come out as + // green-red blobs. + const GLubyte *glVendor = QOpenGLContext::currentContext()->functions()->glGetString(GL_VENDOR); + if (perfLevel < Deformable && glVendor && strstr((char *) glVendor, "ATI")) { + perfLevel = Deformable; + } #endif #ifdef Q_OS_LINUX - // Nouveau drivers can potentially freeze a machine entirely when taking the point-sprite path. - const GLubyte *glVendor = QOpenGLContext::currentContext()->functions()->glGetString(GL_VENDOR); - if (perfLevel < Deformable && glVendor && strstr((const char *) glVendor, "nouveau")) - perfLevel = Deformable; + // Nouveau drivers can potentially freeze a machine entirely when taking the point-sprite path. + const GLubyte *glVendor = QOpenGLContext::currentContext()->functions()->glGetString(GL_VENDOR); + if (perfLevel < Deformable && glVendor && strstr((const char *) glVendor, "nouveau")) + perfLevel = Deformable; #endif + } else { + // Points with a size other than 1 are an optional feature with QRhi + // because some of the underlying APIs have no support for this. + // Therefore, avoid the point sprite path with APIs like Direct3D. + if (perfLevel < Deformable && !m_rhi->isFeatureSupported(QRhi::VertexShaderPointSize)) + perfLevel = Deformable; + } + if (perfLevel >= Colored && !m_color.isValid()) m_color = QColor(Qt::white);//Hidden default, but different from unset @@ -1308,6 +1723,7 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) bool imageLoaded = false; switch (perfLevel) {//Fallthrough intended case Sprites: + { if (!m_spriteEngine) { qWarning() << "ImageParticle: No sprite engine..."; //Sprite performance mode with static image is supported, but not advised @@ -1318,16 +1734,19 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) return; imageLoaded = true; } - m_material = SpriteMaterial::createMaterial(); + m_material = new SpriteMaterial; + ImageMaterialData *state = getState(m_material); if (imageLoaded) - getState(m_material)->texture = QSGPlainTexture::fromImage(image); - getState(m_material)->animSheetSize = QSizeF(image.size() / image.devicePixelRatioF()); + state->texture = QSGPlainTexture::fromImage(image); + state->animSheetSize = QSizeF(image.size() / image.devicePixelRatioF()); if (m_spriteEngine) m_spriteEngine->setCount(m_count); + } Q_FALLTHROUGH(); case Tabled: + { if (!m_material) - m_material = TabledMaterial::createMaterial(); + m_material = new TabledMaterial; if (m_colorTable) { if (m_colorTable->pix.isReady()) @@ -1354,21 +1773,29 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) colortable = QImage(1,1,QImage::Format_ARGB32_Premultiplied); colortable.fill(Qt::white); } - getState(m_material)->colorTable = QSGPlainTexture::fromImage(colortable); - fillUniformArrayFromImage(getState(m_material)->sizeTable, sizetable, UNIFORM_ARRAY_SIZE); - fillUniformArrayFromImage(getState(m_material)->opacityTable, opacitytable, UNIFORM_ARRAY_SIZE); + ImageMaterialData *state = getState(m_material); + state->colorTable = QSGPlainTexture::fromImage(colortable); + fillUniformArrayFromImage(state->sizeTable, sizetable, UNIFORM_ARRAY_SIZE); + fillUniformArrayFromImage(state->opacityTable, opacitytable, UNIFORM_ARRAY_SIZE); + } Q_FALLTHROUGH(); case Deformable: + { if (!m_material) - m_material = DeformableMaterial::createMaterial(); + m_material = new DeformableMaterial; + } Q_FALLTHROUGH(); case Colored: + { if (!m_material) - m_material = ColoredMaterial::createMaterial(); + m_material = new ColoredMaterial; + } Q_FALLTHROUGH(); default://Also Simple + { if (!m_material) - m_material = SimpleMaterial::createMaterial(); + m_material = new SimpleMaterial; + ImageMaterialData *state = getState(m_material); if (!imageLoaded) { if (!m_image || !m_image->pix.isReady()) { if (m_image) @@ -1376,14 +1803,15 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) delete m_material; return; } - //getState(m_material)->texture //TODO: Shouldn't this be better? But not crash? + //state->texture //TODO: Shouldn't this be better? But not crash? // = QQuickItemPrivate::get(this)->sceneGraphContext()->textureForFactory(m_imagePix.textureFactory()); - getState(m_material)->texture = QSGPlainTexture::fromImage(m_image->pix.image()); + state->texture = QSGPlainTexture::fromImage(m_image->pix.image()); } - getState(m_material)->texture->setFiltering(QSGTexture::Linear); - getState(m_material)->entry = (qreal) m_entryEffect; + state->texture->setFiltering(QSGTexture::Linear); + state->entry = (qreal) m_entryEffect; m_material->setFlag(QSGMaterial::Blending | QSGMaterial::RequiresFullMatrix); } + } m_nodes.clear(); for (auto groupId : groupIds()) { @@ -1416,14 +1844,23 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) node->setFlag(QSGNode::OwnsGeometry); node->setGeometry(g); if (perfLevel <= Colored){ - g->setDrawingMode(GL_POINTS); - if (m_debugMode){ - GLfloat pointSizeRange[2]; - QOpenGLContext::currentContext()->functions()->glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange); - qDebug() << "Using point sprites, GL_ALIASED_POINT_SIZE_RANGE " <setDrawingMode(QSGGeometry::DrawPoints); + if (m_debugMode) { + if (m_rhi) { + qDebug("Using point sprites"); + } else { +#if QT_CONFIG(opengl) + GLfloat pointSizeRange[2]; + QOpenGLContext::currentContext()->functions()->glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange); + qDebug() << "Using point sprites, GL_ALIASED_POINT_SIZE_RANGE " <setDrawingMode(GL_TRIANGLES); + } else { + g->setDrawingMode(QSGGeometry::DrawTriangles); + } for (int p=0; p < count; ++p) commit(groupId, p);//commit sets geometry for the node, has its own perfLevel switch @@ -1464,16 +1901,34 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) update(); } -static inline bool isOpenGL(QSGRenderContext *rc) -{ - QSGRendererInterface *rif = rc->sceneGraphContext()->rendererInterface(rc); - return !rif || rif->graphicsApi() == QSGRendererInterface::OpenGL; -} - QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *node, UpdatePaintNodeData *) { - if (!node && !isOpenGL(QQuickItemPrivate::get(this)->sceneGraphRenderContext())) - return nullptr; + if (!m_apiChecked || m_windowChanged) { + m_apiChecked = true; + m_windowChanged = false; + + QSGRenderContext *rc = QQuickItemPrivate::get(this)->sceneGraphRenderContext(); + QSGRendererInterface *rif = rc->sceneGraphContext()->rendererInterface(rc); + if (!rif) + return nullptr; + + QSGRendererInterface::GraphicsApi api = rif->graphicsApi(); + const bool isDirectOpenGL = api == QSGRendererInterface::OpenGL; + const bool isRhi = QSGRendererInterface::isApiRhiBased(api); + + if (!node && !isDirectOpenGL && !isRhi) + return nullptr; + + if (isRhi) + m_rhi = static_cast(rif->getResource(m_window, QSGRendererInterface::RhiResource)); + else + m_rhi = nullptr; + + if (isRhi && !m_rhi) { + qWarning("Failed to query QRhi, particles disabled"); + return nullptr; + } + } if (m_pleaseReset){ if (node) @@ -1541,7 +1996,7 @@ void QQuickImageParticle::prepareNextFrame(QSGNode **node) case Colored: case Simple: default: //Also Simple - getState(m_material)->timestamp = time; + getState(m_material)->timestamp = time; break; } foreach (QSGGeometryNode* node, m_nodes) @@ -1550,6 +2005,7 @@ void QQuickImageParticle::prepareNextFrame(QSGNode **node) void QQuickImageParticle::spritesUpdate(qreal time) { + ImageMaterialData *state = getState(m_material); // Sprite progression handled CPU side, so as to have per-frame control. for (auto groupId : groupIds()) { for (QQuickParticleData* mainDatum : qAsConst(m_system->groupData[groupId]->data)) { @@ -1587,7 +2043,7 @@ void QQuickImageParticle::spritesUpdate(qreal time) } if (m_spriteEngine->sprite(spriteIdx)->reverse())//### Store this in datum too? frameAt = (datum->frameCount - 1) - frameAt; - QSizeF sheetSize = getState(m_material)->animSheetSize; + QSizeF sheetSize = state->animSheetSize; qreal y = datum->animY / sheetSize.height(); qreal w = datum->animWidth / sheetSize.width(); qreal h = datum->animHeight / sheetSize.height(); @@ -1686,6 +2142,7 @@ void QQuickImageParticle::initialize(int gIdx, int pIdx) writeTo->animHeight = m_spriteEngine->spriteHeight(spriteIdx); } } else { + ImageMaterialData *state = getState(m_material); QQuickParticleData* writeTo = getShadowDatum(datum); writeTo->animT = datum->t; writeTo->frameCount = 1; @@ -1694,8 +2151,8 @@ void QQuickImageParticle::initialize(int gIdx, int pIdx) writeTo->animIdx = 0; writeTo->animT = 0; writeTo->animX = writeTo->animY = 0; - writeTo->animWidth = getState(m_material)->animSheetSize.width(); - writeTo->animHeight = getState(m_material)->animSheetSize.height(); + writeTo->animWidth = state->animSheetSize.width(); + writeTo->animHeight = state->animSheetSize.height(); } Q_FALLTHROUGH(); case Tabled: diff --git a/src/particles/qquickimageparticle_p.h b/src/particles/qquickimageparticle_p.h index 95323c25a6..059cf67019 100644 --- a/src/particles/qquickimageparticle_p.h +++ b/src/particles/qquickimageparticle_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQuick module of the Qt Toolkit. @@ -37,8 +37,8 @@ ** ****************************************************************************/ -#ifndef ULTRAPARTICLE_H -#define ULTRAPARTICLE_H +#ifndef QQUICKIMAGEPARTICLE_P_H +#define QQUICKIMAGEPARTICLE_P_H // // W A R N I N G @@ -50,21 +50,25 @@ // // We mean it. // + #include "qquickparticlepainter_p.h" #include "qquickdirection_p.h" #include #include -#include #include +#include QT_BEGIN_NAMESPACE class ImageMaterialData; class QSGGeometryNode; +class QSGMaterial; class QQuickSprite; class QQuickStochasticEngine; +class QRhi; + struct SimpleVertex { float x; float y; @@ -153,6 +157,12 @@ struct Vertices { Vertex v4; }; +class ImageMaterial : public QSGMaterial +{ +public: + virtual ImageMaterialData *state() = 0; +}; + class QQuickImageParticle : public QQuickParticlePainter { Q_OBJECT @@ -439,14 +449,17 @@ private: } } - template - static MaterialData* getState(QSGMaterial* m) { - return static_cast *>(m)->state(); + ImageMaterialData *getState(QSGMaterial *m) { + return static_cast(m)->state(); } + EntryEffect m_entryEffect; Status m_status; int m_startedImageLoading; + QRhi *m_rhi; + bool m_apiChecked; }; QT_END_NAMESPACE -#endif // ULTRAPARTICLE_H + +#endif // QQUICKIMAGEPARTICLE_P_H diff --git a/src/particles/qquickparticlepainter.cpp b/src/particles/qquickparticlepainter.cpp index e762b3ae1d..78e11fafcf 100644 --- a/src/particles/qquickparticlepainter.cpp +++ b/src/particles/qquickparticlepainter.cpp @@ -70,6 +70,7 @@ QQuickParticlePainter::QQuickParticlePainter(QQuickItem *parent) , m_count(0) , m_pleaseReset(true) , m_window(nullptr) + , m_windowChanged(false) , m_groupIdsNeedRecalculation(false) { } @@ -80,6 +81,7 @@ void QQuickParticlePainter::itemChange(ItemChange change, const ItemChangeData & if (m_window) disconnect(m_window, SIGNAL(sceneGraphInvalidated()), this, SLOT(sceneGraphInvalidated())); m_window = data.window; + m_windowChanged = true; if (m_window) connect(m_window, SIGNAL(sceneGraphInvalidated()), this, SLOT(sceneGraphInvalidated()), Qt::DirectConnection); } diff --git a/src/particles/qquickparticlepainter_p.h b/src/particles/qquickparticlepainter_p.h index ac14a18103..16fc6b6f45 100644 --- a/src/particles/qquickparticlepainter_p.h +++ b/src/particles/qquickparticlepainter_p.h @@ -141,6 +141,7 @@ protected: QPointF m_systemOffset; QQuickWindow *m_window; + bool m_windowChanged; private: // methods void recalculateGroupIds() const; diff --git a/src/particles/shaders_ng/compile.bat b/src/particles/shaders_ng/compile.bat new file mode 100755 index 0000000000..2376d5bf6d --- /dev/null +++ b/src/particles/shaders_ng/compile.bat @@ -0,0 +1,53 @@ +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: +:: Copyright (C) 2019 The Qt Company Ltd. +:: Contact: https://www.qt.io/licensing/ +:: +:: This file is part of the QtQuick module of the Qt Toolkit. +:: +:: $QT_BEGIN_LICENSE:LGPL$ +:: Commercial License Usage +:: Licensees holding valid commercial Qt licenses may use this file in +:: accordance with the commercial license agreement provided with the +:: Software or, alternatively, in accordance with the terms contained in +:: a written agreement between you and The Qt Company. For licensing terms +:: and conditions see https://www.qt.io/terms-conditions. For further +:: information use the contact form at https://www.qt.io/contact-us. +:: +:: GNU Lesser General Public License Usage +:: Alternatively, this file may be used under the terms of the GNU Lesser +:: General Public License version 3 as published by the Free Software +:: Foundation and appearing in the file LICENSE.LGPL3 included in the +:: packaging of this file. Please review the following information to +:: ensure the GNU Lesser General Public License version 3 requirements +:: will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +:: +:: GNU General Public License Usage +:: Alternatively, this file may be used under the terms of the GNU +:: General Public License version 2.0 or (at your option) the GNU General +:: Public license version 3 or any later version approved by the KDE Free +:: Qt Foundation. The licenses are as published by the Free Software +:: Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +:: included in the packaging of this file. Please review the following +:: information to ensure the GNU General Public License requirements will +:: be met: https://www.gnu.org/licenses/gpl-2.0.html and +:: https://www.gnu.org/licenses/gpl-3.0.html. +:: +:: $QT_END_LICENSE$ +:: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +qsb -b --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_simple.vert.qsb imageparticle.vert +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_simple.frag.qsb imageparticle.frag + +qsb -DTABLE -DDEFORM -DCOLOR -b --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_tabled.vert.qsb imageparticle.vert +qsb -DTABLE -DDEFORM -DCOLOR --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_tabled.frag.qsb imageparticle.frag + +qsb -DDEFORM -DCOLOR -b --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_deformed.vert.qsb imageparticle.vert +qsb -DDEFORM -DCOLOR --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_deformed.frag.qsb imageparticle.frag + +qsb -DSPRITE -DTABLE -DDEFORM -DCOLOR -b --zorder-loc 8 --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_sprite.vert.qsb imageparticle.vert +qsb -DSPRITE -DTABLE -DDEFORM -DCOLOR --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_sprite.frag.qsb imageparticle.frag + +qsb -DCOLOR -b --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_colored.vert.qsb imageparticle.vert +qsb -DCOLOR --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_colored.frag.qsb imageparticle.frag diff --git a/src/particles/shaders_ng/imageparticle.frag b/src/particles/shaders_ng/imageparticle.frag new file mode 100644 index 0000000000..cefb7d2d75 --- /dev/null +++ b/src/particles/shaders_ng/imageparticle.frag @@ -0,0 +1,55 @@ +#version 440 + +#if defined(TABLE) +layout(location = 0) in vec2 tt; +#endif + +#if defined(SPRITE) +layout(location = 1) in vec4 fTexS; +#elif defined(DEFORM) +layout(location = 1) in vec2 fTex; +#endif + +#if defined(COLOR) +layout(location = 2) in vec4 fColor; +#else +layout(location = 2) in float fFade; +#endif + +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform buf { + mat4 matrix; + float opacity; + float entry; + float timestamp; + float sizetable[64]; + float opacitytable[64]; +} ubuf; + +layout(binding = 1) uniform sampler2D _qt_texture; + +#if defined(TABLE) || defined(SPRITE) +layout(binding = 2) uniform sampler2D colortable; +#endif + +void main() +{ +#if defined(SPRITE) + fragColor = mix(texture(_qt_texture, fTexS.xy), texture(_qt_texture, fTexS.zw), tt.y) + * fColor + * texture(colortable, tt) + * ubuf.opacity; +#elif defined(TABLE) + fragColor = texture(_qt_texture, fTex) + * fColor + * texture(colortable, tt) + * ubuf.opacity; +#elif defined(DEFORM) + fragColor = texture(_qt_texture, fTex) * fColor * ubuf.opacity; +#elif defined(COLOR) + fragColor = texture(_qt_texture, gl_PointCoord) * fColor * ubuf.opacity; +#else + fragColor = texture(_qt_texture, gl_PointCoord) * fFade * ubuf.opacity; +#endif +} diff --git a/src/particles/shaders_ng/imageparticle.vert b/src/particles/shaders_ng/imageparticle.vert new file mode 100644 index 0000000000..870139452b --- /dev/null +++ b/src/particles/shaders_ng/imageparticle.vert @@ -0,0 +1,145 @@ +#version 440 + +layout(location = 1) in vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize +layout(location = 2) in vec4 vVec; // x,y = constant velocity, z,w = acceleration + +#if defined(DEFORM) +layout(location = 0) in vec4 vPosTex; +#else +layout(location = 0) in vec2 vPos; +#endif + +#if defined(COLOR) +layout(location = 3) in vec4 vColor; +#endif + +#if defined(DEFORM) +layout(location = 4) in vec4 vDeformVec; // x,y x unit vector; z,w = y unit vector +layout(location = 5) in vec3 vRotation; // x = radians of rotation, y = rotation velocity, z = bool autoRotate +#endif + +#if defined(SPRITE) +layout(location = 6) in vec3 vAnimData; // w,h(premultiplied of anim), interpolation progress +layout(location = 7) in vec4 vAnimPos; // x,y, x,y (two frames for interpolation) +#endif + +#if defined(TABLE) +layout(location = 0) out vec2 tt; //y is progress if Sprite mode +#endif + +#if defined(SPRITE) +layout(location = 1) out vec4 fTexS; +#elif defined(DEFORM) +layout(location = 1) out vec2 fTex; +#endif + +#if defined(COLOR) +layout(location = 2) out vec4 fColor; +#else +layout(location = 2) out float fFade; +#endif + +layout(std140, binding = 0) uniform buf { + mat4 matrix; + float opacity; + float entry; + float timestamp; + float sizetable[64]; + float opacitytable[64]; +} ubuf; + +out gl_PerVertex { vec4 gl_Position; float gl_PointSize; }; + +void main() +{ + float t = (ubuf.timestamp - vData.x) / vData.y; + if (t < 0. || t > 1.) { +#if defined(DEFORM) + gl_Position = ubuf.matrix * vec4(vPosTex.x, vPosTex.y, 0., 1.); +#else + gl_PointSize = 0.; +#endif + } else { +#if defined(SPRITE) + tt.y = vAnimData.z; + + // Calculate frame location in texture + fTexS.xy = vAnimPos.xy + vPosTex.zw * vAnimData.xy; + + // Next frame is also passed, for interpolation + fTexS.zw = vAnimPos.zw + vPosTex.zw * vAnimData.xy; + +#elif defined(DEFORM) + fTex = vPosTex.zw; +#endif + float currentSize = mix(vData.z, vData.w, t * t); + float fade = 1.; + float fadeIn = min(t * 10., 1.); + float fadeOut = 1. - clamp((t - 0.75) * 4.,0., 1.); + +#if defined(TABLE) + currentSize = currentSize * ubuf.sizetable[int(floor(t*64.))]; + fade = fade * ubuf.opacitytable[int(floor(t*64.))]; +#endif + + if (ubuf.entry == 1.) + fade = fade * fadeIn * fadeOut; + else if (ubuf.entry == 2.) + currentSize = currentSize * fadeIn * fadeOut; + + if (currentSize <= 0.) { +#if defined(DEFORM) + gl_Position = ubuf.matrix * vec4(vPosTex.x, vPosTex.y, 0., 1.); +#else + gl_PointSize = 0.; +#endif + } else { + if (currentSize < 3.) // Sizes too small look jittery as they move + currentSize = 3.; + + vec2 pos; +#if defined(DEFORM) + float rotation = vRotation.x + vRotation.y * t * vData.y; + if (vRotation.z == 1.0) { + vec2 curVel = vVec.zw * t * vData.y + vVec.xy; + if (length(curVel) > 0.) + rotation += atan(curVel.y, curVel.x); + } + vec2 trigCalcs = vec2(cos(rotation), sin(rotation)); + vec4 deform = vDeformVec * currentSize * (vPosTex.zzww - 0.5); + vec4 rotatedDeform = deform.xxzz * trigCalcs.xyxy; + rotatedDeform = rotatedDeform + (deform.yyww * trigCalcs.yxyx * vec4(-1.,1.,-1.,1.)); + /* The readable version: + vec2 xDeform = vDeformVec.xy * currentSize * (vTex.x-0.5); + vec2 yDeform = vDeformVec.zw * currentSize * (vTex.y-0.5); + vec2 xRotatedDeform; + xRotatedDeform.x = trigCalcs.x*xDeform.x - trigCalcs.y*xDeform.y; + xRotatedDeform.y = trigCalcs.y*xDeform.x + trigCalcs.x*xDeform.y; + vec2 yRotatedDeform; + yRotatedDeform.x = trigCalcs.x*yDeform.x - trigCalcs.y*yDeform.y; + yRotatedDeform.y = trigCalcs.y*yDeform.x + trigCalcs.x*yDeform.y; + */ + pos = vPosTex.xy + + rotatedDeform.xy + + rotatedDeform.zw + + vVec.xy * t * vData.y // apply velocity + + 0.5 * vVec.zw * pow(t * vData.y, 2.); // apply acceleration +#else + pos = vPos + + vVec.xy * t * vData.y // apply velocity vector.. + + 0.5 * vVec.zw * pow(t * vData.y, 2.); + gl_PointSize = currentSize; +#endif + gl_Position = ubuf.matrix * vec4(pos.x, pos.y, 0, 1); + +#if defined(COLOR) + fColor = vColor * fade; +#else + fFade = fade; +#endif +#if defined(TABLE) + tt.x = t; +#endif + } + } +} diff --git a/src/particles/shaders_ng/imageparticle_colored.frag.qsb b/src/particles/shaders_ng/imageparticle_colored.frag.qsb new file mode 100644 index 0000000000..7ae640d224 Binary files /dev/null and b/src/particles/shaders_ng/imageparticle_colored.frag.qsb differ diff --git a/src/particles/shaders_ng/imageparticle_colored.vert.qsb b/src/particles/shaders_ng/imageparticle_colored.vert.qsb new file mode 100644 index 0000000000..0e2938b72c Binary files /dev/null and b/src/particles/shaders_ng/imageparticle_colored.vert.qsb differ diff --git a/src/particles/shaders_ng/imageparticle_deformed.frag.qsb b/src/particles/shaders_ng/imageparticle_deformed.frag.qsb new file mode 100644 index 0000000000..fa9d9d35bb Binary files /dev/null and b/src/particles/shaders_ng/imageparticle_deformed.frag.qsb differ diff --git a/src/particles/shaders_ng/imageparticle_deformed.vert.qsb b/src/particles/shaders_ng/imageparticle_deformed.vert.qsb new file mode 100644 index 0000000000..65092d5b26 Binary files /dev/null and b/src/particles/shaders_ng/imageparticle_deformed.vert.qsb differ diff --git a/src/particles/shaders_ng/imageparticle_simple.frag.qsb b/src/particles/shaders_ng/imageparticle_simple.frag.qsb new file mode 100644 index 0000000000..a5874cba24 Binary files /dev/null and b/src/particles/shaders_ng/imageparticle_simple.frag.qsb differ diff --git a/src/particles/shaders_ng/imageparticle_simple.vert.qsb b/src/particles/shaders_ng/imageparticle_simple.vert.qsb new file mode 100644 index 0000000000..da815d7e19 Binary files /dev/null and b/src/particles/shaders_ng/imageparticle_simple.vert.qsb differ diff --git a/src/particles/shaders_ng/imageparticle_sprite.frag.qsb b/src/particles/shaders_ng/imageparticle_sprite.frag.qsb new file mode 100644 index 0000000000..778550344b Binary files /dev/null and b/src/particles/shaders_ng/imageparticle_sprite.frag.qsb differ diff --git a/src/particles/shaders_ng/imageparticle_sprite.vert.qsb b/src/particles/shaders_ng/imageparticle_sprite.vert.qsb new file mode 100644 index 0000000000..45b21ace8a Binary files /dev/null and b/src/particles/shaders_ng/imageparticle_sprite.vert.qsb differ diff --git a/src/particles/shaders_ng/imageparticle_tabled.frag.qsb b/src/particles/shaders_ng/imageparticle_tabled.frag.qsb new file mode 100644 index 0000000000..c5dcc2c68f Binary files /dev/null and b/src/particles/shaders_ng/imageparticle_tabled.frag.qsb differ diff --git a/src/particles/shaders_ng/imageparticle_tabled.vert.qsb b/src/particles/shaders_ng/imageparticle_tabled.vert.qsb new file mode 100644 index 0000000000..ea42607570 Binary files /dev/null and b/src/particles/shaders_ng/imageparticle_tabled.vert.qsb differ -- cgit v1.2.3 From 7b130535cf590b310f23c8167986588d3982ad20 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Wed, 7 Aug 2019 15:27:24 +0200 Subject: Implement QSGRenderNode for the rhi path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The documentation is also refined and extended. Revise the rendernode example as well: make it possible to test and demonstrate both scissor and stencil based clipping. An implementation of the triangle for another graphics API should follow in a separate patch at a later point. For now only OpenGL is supported in combination with the RHI. Change-Id: I7ef9f6c6e0b44f1bdf44c9266ea3fa4736367a5d Reviewed-by: Christian Strømme --- .../scenegraph/rendernode/customrenderitem.cpp | 28 +++--- .../quick/scenegraph/rendernode/d3d12renderer.cpp | 6 +- examples/quick/scenegraph/rendernode/main.qml | 81 +++++++++++++--- .../quick/scenegraph/rendernode/openglrenderer.cpp | 20 +++- src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp | 108 ++++++++++++++++++++- src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h | 2 + src/quick/scenegraph/coreapi/qsgrendernode.cpp | 103 ++++++++++++++------ 7 files changed, 284 insertions(+), 64 deletions(-) diff --git a/examples/quick/scenegraph/rendernode/customrenderitem.cpp b/examples/quick/scenegraph/rendernode/customrenderitem.cpp index 8f248e2ecb..9dbe8d86a0 100644 --- a/examples/quick/scenegraph/rendernode/customrenderitem.cpp +++ b/examples/quick/scenegraph/rendernode/customrenderitem.cpp @@ -71,23 +71,29 @@ QSGNode *CustomRenderItem::updatePaintNode(QSGNode *node, UpdatePaintNodeData *) if (!ri) return nullptr; switch (ri->graphicsApi()) { - case QSGRendererInterface::OpenGL: + case QSGRendererInterface::OpenGL: + Q_FALLTHROUGH(); + case QSGRendererInterface::OpenGLRhi: #if QT_CONFIG(opengl) - n = new OpenGLRenderNode(this); - break; + n = new OpenGLRenderNode(this); #endif - case QSGRendererInterface::Direct3D12: + break; + + case QSGRendererInterface::Direct3D12: // ### Qt 6: remove #if QT_CONFIG(d3d12) - n = new D3D12RenderNode(this); - break; + n = new D3D12RenderNode(this); #endif - case QSGRendererInterface::Software: - n = new SoftwareRenderNode(this); - break; + break; + + case QSGRendererInterface::Software: + n = new SoftwareRenderNode(this); + break; - default: - return nullptr; + default: + break; } + if (!n) + qWarning("QSGRendererInterface reports unknown graphics API %d", ri->graphicsApi()); } return n; diff --git a/examples/quick/scenegraph/rendernode/d3d12renderer.cpp b/examples/quick/scenegraph/rendernode/d3d12renderer.cpp index df0e29eb67..878b022950 100644 --- a/examples/quick/scenegraph/rendernode/d3d12renderer.cpp +++ b/examples/quick/scenegraph/rendernode/d3d12renderer.cpp @@ -54,6 +54,8 @@ #include #include +// ### Qt 6: remove + #if QT_CONFIG(d3d12) D3D12RenderNode::D3D12RenderNode(QQuickItem *item) @@ -166,8 +168,8 @@ void D3D12RenderNode::init() psoDesc.RasterizerState = rastDesc; psoDesc.BlendState = blendDesc; // No depth. The correct stacking of the item is ensured by the projection matrix. - // Do not bother with stencil since we do not apply clipping in the - // example. If clipping is desired, render() needs to set a different PSO + // Note that this does not support clipping. + // If clipping is desired, render() needs to set a different PSO // with stencil enabled whenever the RenderState indicates so. psoDesc.SampleMask = UINT_MAX; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; diff --git a/examples/quick/scenegraph/rendernode/main.qml b/examples/quick/scenegraph/rendernode/main.qml index d0ba4a4669..85060261c5 100644 --- a/examples/quick/scenegraph/rendernode/main.qml +++ b/examples/quick/scenegraph/rendernode/main.qml @@ -53,23 +53,55 @@ import SceneGraphRendering 2.0 Item { Rectangle { + id: bg anchors.fill: parent gradient: Gradient { GradientStop { position: 0; color: "steelblue" } GradientStop { position: 1; color: "black" } } - CustomRenderItem { - id: renderer + MouseArea { anchors.fill: parent - anchors.margins: 10 + acceptedButtons: Qt.LeftButton | Qt.RightButton + onClicked: { + if (mouse.button === Qt.LeftButton) { + clipper.clip = !clipper.clip + } else if (mouse.button === Qt.RightButton) { + nonRectClipAnim.running = !nonRectClipAnim.running + if (!nonRectClipAnim.running) + clipper.rotation = 0; + } + } + } + + Rectangle { + id: clipper + width: parent.width / 2 + height: parent.height / 2 + anchors.centerIn: parent + border.color: "yellow" + border.width: 2 + color: "transparent" + NumberAnimation on rotation { + id: nonRectClipAnim + from: 0; to: 360; duration: 5000; loops: Animation.Infinite + running: false + } + + CustomRenderItem { + id: renderer + width: bg.width - 20 + height: bg.height - 20 + x: -clipper.x + 10 + y: -clipper.y + 10 - transform: [ - Rotation { id: rotation; axis.x: 0; axis.z: 0; axis.y: 1; angle: 0; origin.x: renderer.width / 2; origin.y: renderer.height / 2; }, - Translate { id: txOut; x: -renderer.width / 2; y: -renderer.height / 2 }, - Scale { id: scale; }, - Translate { id: txIn; x: renderer.width / 2; y: renderer.height / 2 } - ] + transform: [ + Rotation { id: rotation; axis.x: 0; axis.z: 0; axis.y: 1; angle: 0; origin.x: renderer.width / 2; origin.y: renderer.height / 2; }, + Translate { id: txOut; x: -renderer.width / 2; y: -renderer.height / 2 }, + Scale { id: scale; }, + Translate { id: txIn; x: renderer.width / 2; y: renderer.height / 2 } + ] + } } SequentialAnimation { @@ -94,17 +126,34 @@ Item { Text { id: label - anchors.bottom: renderer.bottom - anchors.left: renderer.left - anchors.right: renderer.right + anchors.bottom: parent.bottom + anchors.left: parent.left anchors.margins: 20 + color: "yellow" wrapMode: Text.WordWrap property int api: GraphicsInfo.api - text: "Custom rendering via the graphics API " - + (api === GraphicsInfo.OpenGL ? "OpenGL" - : api === GraphicsInfo.Direct3D12 ? "Direct3D 12" - : api === GraphicsInfo.Software ? "Software" : "") + text: { + var apiStr; + switch (api) { + case GraphicsInfo.OpenGL: apiStr = "OpenGL (direct)"; break; + case GraphicsInfo.Direct3D12: apiStr = "Direct3D 12 (direct)"; break; + case GraphicsInfo.Software: apiStr = "Software (QPainter)"; break; + case GraphicsInfo.OpenGLRhi: apiStr = "OpenGL (RHI)"; break; + // the example has no other QSGRenderNode subclasses + default: apiStr = ""; break; + } + "Custom rendering via the graphics API " + apiStr + + "\nLeft click to toggle clipping to yellow rect" + + "\nRight click to rotate (can be used to exercise stencil clip instead of scissor)" + } + } + + Text { + id: label2 + anchors.top: parent.top + anchors.right: parent.right color: "yellow" + text: "Clip: " + (clipper.clip ? "ON" : "OFF") + " Rotation: " + (nonRectClipAnim.running ? "ON" : "OFF") } } } diff --git a/examples/quick/scenegraph/rendernode/openglrenderer.cpp b/examples/quick/scenegraph/rendernode/openglrenderer.cpp index 3c68830db6..5e6b9e3656 100644 --- a/examples/quick/scenegraph/rendernode/openglrenderer.cpp +++ b/examples/quick/scenegraph/rendernode/openglrenderer.cpp @@ -148,17 +148,33 @@ void OpenGLRenderNode::render(const RenderState *state) m_program->enableAttributeArray(0); m_program->enableAttributeArray(1); - // Note that clipping (scissor or stencil) is ignored in this example. + // We are prepared both for the legacy (direct OpenGL) and the modern + // (abstracted by RHI) OpenGL scenegraph. So set all the states that are + // important to us. + + f->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); f->glEnable(GL_BLEND); f->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + // Clip support. + if (state->scissorEnabled()) { + f->glEnable(GL_SCISSOR_TEST); + const QRect r = state->scissorRect(); // already bottom-up + f->glScissor(r.x(), r.y(), r.width(), r.height()); + } + if (state->stencilEnabled()) { + f->glEnable(GL_STENCIL_TEST); + f->glStencilFunc(GL_EQUAL, state->stencilValue(), 0xFF); + f->glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + } + f->glDrawArrays(GL_TRIANGLES, 0, 3); } QSGRenderNode::StateFlags OpenGLRenderNode::changedStates() const { - return BlendState; + return BlendState | ScissorState | StencilState; } QSGRenderNode::RenderingFlags OpenGLRenderNode::flags() const diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index 3d8e3291b2..293cc4cb6b 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -2665,7 +2665,8 @@ void Renderer::updateClipState(const QSGClipNode *clipList, Batch *batch) // RHI { // Note: No use of the clip-related speparate m_current* vars is allowed // here. All stored in batch->clipState instead. To collect state during - // renderBatches(), m_currentClipState is used. + // the prepare steps, m_currentClipState is used. It should not be used in + // the render steps afterwards. // The stenciling logic is slightly different from the legacy GL path as we // cannot just randomly clear the stencil buffer. We now put all clip @@ -4089,7 +4090,7 @@ void Renderer::renderBatches() if (b->merged) ok = prepareRenderMergedBatch(b, &renderBatch); else if (b->isRenderNode) - ok = false; // ### + ok = prepareRhiRenderNode(b, &renderBatch); else ok = prepareRenderUnmergedBatch(b, &renderBatch); if (ok) @@ -4120,7 +4121,7 @@ void Renderer::renderBatches() if (renderBatch->batch->merged) renderMergedBatch(renderBatch); else if (renderBatch->batch->isRenderNode) - Q_UNREACHABLE(); // ### + renderRhiRenderNode(renderBatch->batch); else renderUnmergedBatch(renderBatch); } @@ -4359,7 +4360,7 @@ struct RenderNodeState : public QSGRenderNode::RenderState bool m_stencilEnabled; }; -void Renderer::renderRenderNode(Batch *batch) +void Renderer::renderRenderNode(Batch *batch) // legacy (GL-only) { if (Q_UNLIKELY(debug_render())) qDebug() << " -" << batch << "rendernode"; @@ -4475,6 +4476,105 @@ void Renderer::renderRenderNode(Batch *batch) glBindFramebuffer(GL_FRAMEBUFFER, prevFbo); } +bool Renderer::prepareRhiRenderNode(Batch *batch, PreparedRenderBatch *renderBatch) // split prepare-render (RHI only) +{ + if (Q_UNLIKELY(debug_render())) + qDebug() << " -" << batch << "rendernode"; + + Q_ASSERT(batch->first->isRenderNode); + RenderNodeElement *e = static_cast(batch->first); + + setActiveRhiShader(nullptr, nullptr); + + QSGNode *clip = e->renderNode->parent(); + QSGRenderNodePrivate *rd = QSGRenderNodePrivate::get(e->renderNode); + rd->m_clip_list = nullptr; + while (clip != rootNode()) { + if (clip->type() == QSGNode::ClipNodeType) { + rd->m_clip_list = static_cast(clip); + break; + } + clip = clip->parent(); + } + + updateClipState(rd->m_clip_list, batch); + + renderBatch->batch = batch; + renderBatch->sms = nullptr; + + return true; +} + +void Renderer::renderRhiRenderNode(const Batch *batch) // split prepare-render (RHI only) +{ + if (batch->clipState.type & ClipState::StencilClip) + enqueueStencilDraw(batch); + + RenderNodeElement *e = static_cast(batch->first); + QSGRenderNodePrivate *rd = QSGRenderNodePrivate::get(e->renderNode); + + QMatrix4x4 pm = projectionMatrix(); + if (m_useDepthBuffer) { + pm(2, 2) = m_zRange; + pm(2, 3) = 1.0f - e->order * m_zRange; + } + + RenderNodeState state; + state.m_projectionMatrix = ± + const std::array scissor = batch->clipState.scissor.scissor(); + state.m_scissorRect = QRect(scissor[0], scissor[1], scissor[2], scissor[3]); + state.m_stencilValue = batch->clipState.stencilRef; + state.m_scissorEnabled = batch->clipState.type & ClipState::ScissorClip; + state.m_stencilEnabled = batch->clipState.type & ClipState::StencilClip; + + QSGNode *xform = e->renderNode->parent(); + QMatrix4x4 matrix; + QSGNode *root = rootNode(); + if (e->root) { + matrix = qsg_matrixForRoot(e->root); + root = e->root->sgNode; + } + while (xform != root) { + if (xform->type() == QSGNode::TransformNodeType) { + matrix = matrix * static_cast(xform)->combinedMatrix(); + break; + } + xform = xform->parent(); + } + rd->m_matrix = &matrix; + + QSGNode *opacity = e->renderNode->parent(); + rd->m_opacity = 1.0; + while (opacity != rootNode()) { + if (opacity->type() == QSGNode::OpacityNodeType) { + rd->m_opacity = static_cast(opacity)->combinedOpacity(); + break; + } + opacity = opacity->parent(); + } + + const QSGRenderNode::StateFlags changes = e->renderNode->changedStates(); + + QRhiCommandBuffer *cb = commandBuffer(); + cb->beginExternal(); + e->renderNode->render(&state); + cb->endExternal(); + + rd->m_matrix = nullptr; + rd->m_clip_list = nullptr; + + if (changes & QSGRenderNode::ViewportState) + m_pstate.viewportSet = false; + + if (changes & QSGRenderNode::ScissorState) + m_pstate.scissorSet = false; + + // Do not bother with RenderTargetState. Where applicable, endExternal() + // ensures the correct target is rebound. For others (like Vulkan) it makes + // no sense since render() could not possibly do that on our command buffer + // which is in renderpass recording state. +} + void Renderer::setCustomRenderMode(const QByteArray &mode) { if (mode.isEmpty()) diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h index ea9dab244f..4e374522d4 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h @@ -817,6 +817,8 @@ private: void enqueueStencilDraw(const Batch *batch); const QMatrix4x4 &matrixForRoot(Node *node); void renderRenderNode(Batch *batch); + bool prepareRhiRenderNode(Batch *batch, PreparedRenderBatch *renderBatch); + void renderRhiRenderNode(const Batch *batch); void setActiveShader(QSGMaterialShader *program, ShaderManager::Shader *shader); void setActiveRhiShader(QSGMaterialRhiShader *program, ShaderManager::Shader *shader); diff --git a/src/quick/scenegraph/coreapi/qsgrendernode.cpp b/src/quick/scenegraph/coreapi/qsgrendernode.cpp index df3fa16a32..2892f2f966 100644 --- a/src/quick/scenegraph/coreapi/qsgrendernode.cpp +++ b/src/quick/scenegraph/coreapi/qsgrendernode.cpp @@ -81,8 +81,10 @@ QSGRenderNodePrivate::QSGRenderNodePrivate() } /*! - This function should return a mask where each bit represents graphics states changed by - the \l render() function: + When the underlying rendering API is OpenGL, this function should return a + mask where each bit represents graphics states changed by the \l render() + function: + \list \li DepthState - depth write mask, depth test enabled, depth comparison function \li StencilState - stencil write masks, stencil test enabled, stencil operations, @@ -95,6 +97,29 @@ QSGRenderNodePrivate::QSGRenderNodePrivate() \li RenderTargetState - render target \endlist + With APIs other than OpenGL, the only relevant values are the ones that + correspond to dynamic state changes recorded on the command list/buffer. + For example, RSSetViewports, RSSetScissorRects, OMSetBlendFactor, + OMSetStencilRef in case of D3D12, or vkCmdSetViewport, vkCmdSetScissor, + vkCmdSetBlendConstants, vkCmdSetStencilRef in case of Vulkan, and only when + such commands were added to the scenegraph's command list queried via the + QSGRendererInterface::CommandList resource enum. States set in pipeline + state objects do not need to be reported here. Similarly, draw call related + settings (pipeline states, descriptor sets, vertex or index buffer + bindings, root signature, descriptor heaps, etc.) are always set again by + the scenegraph so render() can freely change them. + + \note RenderTargetState is no longer supported with APIs like Vulkan. This + is by nature. render() is invoked while the Qt Quick scenegraph's main + command buffer is recording a renderpass, so there is no possibility of + changing the target and starting another renderpass (on that command buffer + at least). Therefore returning a value with RenderTargetState set is not + sensible. + + The software backend exposes its QPainter and saves and restores before and + after invoking render(). Therefore reporting any changed states from here + is not necessary. + The function is called by the renderer so it can reset the states after rendering this node. This makes the implementation of render() simpler since it does not have to query and restore these states. @@ -102,19 +127,6 @@ QSGRenderNodePrivate::QSGRenderNodePrivate() The default implementation returns 0, meaning no relevant state was changed in render(). - With APIs other than OpenGL the relevant states are only those that are set - via the command list (for example, OMSetRenderTargets, RSSetViewports, - RSSetScissorRects, OMSetBlendFactor, OMSetStencilRef in case of D3D12), and - only when such commands were added to the scenegraph's command list queried - via the QSGRendererInterface::CommandList resource enum. States set in - pipeline state objects do not need to be reported here. Similarly, draw - call related settings (root signature, descriptor heaps, etc.) are always - set again by the scenegraph so render() can freely change them. - - The software backend exposes its QPainter and saves and restores before and - after invoking render(). Therefore reporting any changed states from here - is not necessary. - \note This function may be called before render(). */ QSGRenderNode::StateFlags QSGRenderNode::changedStates() const @@ -149,18 +161,31 @@ QSGRenderNode::StateFlags QSGRenderNode::changedStates() const QQuickFramebufferObject, QQuickWindow::beforeRendering(), or the equivalents of those for APIs other than OpenGL. - Clip information is calculated before the function is called, it is however - not enabled. Implementations wishing to take clipping into account can set - up scissoring or stencil based on the information in \a state. Some - scenegraph backends, software in particular, use no scissor or stencil. - There the clip region is provided as an ordinary QRegion. + \note QSGRenderNode can perform significantly better than texture-based + approaches (such as, QQuickFramebufferObject), especially on systems where + the fragment processing power is limited. This is because it avoids + rendering to a texture and then drawing a textured quad. Rather, + QSGRenderNode allows recording draw calls in line with the scenegraph's + other commands, avoiding an additional render target and the potentially + expensive texturing and blending. + + Clip information is calculated before the function is called. + Implementations wishing to take clipping into account can set up scissoring + or stencil based on the information in \a state. The stencil buffer is + filled with the necessary clip shapes, but it is up to the implementation + to enable stencil testing. + + Some scenegraph backends, software in particular, use no scissor or + stencil. There the clip region is provided as an ordinary QRegion. + + With the legacy, direct OpenGL based renderer, the following states are set + on the render thread's context before this function is called: - For OpenGL the following states are set on the render thread's context - before this function is called: \list + \li glColorMask(true, true, true, true) \li glDepthMask(false) \li glDisable(GL_DEPTH_TEST) - \li glStencilFunc(GL_EQUAL, state.stencilValue, 0xff) depending on clip + \li glStencilFunc(GL_EQUAL, state.stencilValue, 0xff); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP) depending on clip \li glScissor(state.scissorRect.x(), state.scissorRect.y(), state.scissorRect.width(), state.scissorRect.height()) depending on clip \li glEnable(GL_BLEND) @@ -168,23 +193,42 @@ QSGRenderNode::StateFlags QSGRenderNode::changedStates() const \li glDisable(GL_CULL_FACE) \endlist - States that are not listed above, but are included in \l StateFlags, can + States that are not listed above, but are covered by \l StateFlags, can have arbitrary values. + \note There is no state set with other graphics APIs, considering that many + of them do not have a concept of the traditional OpenGL state machine. + Rather, it is up to the implementation to create pipeline state objects + with the desired blending, scissor, and stencil tests enabled. Note that + this also includes OpenGL via the RHI. New QSGRenderNode implementations + are recommended to set all scissor, stencil and blend state explicitly (as + shown in the above list), even if they are targeting OpenGL. + \l changedStates() should return which states this function changes. If a state is not covered by \l StateFlags, the state should be set to the default value according to the OpenGL specification. For other APIs, see the documentation for changedStates() for more information. - \note Depth writes are disabled when this function is called (for example, - glDepthMask(false) in case of OpenGL). Enabling depth writes can lead to - unexpected results, depending on the scenegraph backend in use, so nodes - should avoid this. + \note Depth writes are disabled when this function is called + (glDepthMask(false) with OpenGL). Enabling depth writes can lead to + unexpected results, depending on the scenegraph backend in use and the + content in the scene, so exercise caution with this. For APIs other than OpenGL, it will likely be necessary to query certain API-specific resources (for example, the graphics device or the command list/buffer to add the commands to). This is done via QSGRendererInterface. + Assume nothing about the pipelines and dynamic states bound on the command + list/buffer when this function is called. + + With some graphics APIs it can be necessary to also connect to the + QQuickWindow::beforeRendering() signal, because that is emitted before + recording the beginning of a renderpass on the command buffer + (vkCmdBeginRenderPass with Vulkan, or starting to encode via + MTLRenderCommandEncoder in case of Metal). Recording copy operations cannot + be done inside render() with such APIs. Rather, do it in the slot connected + (with DirectConnection) to the beforeRendering signal. + \sa QSGRendererInterface, QQuickWindow::rendererInterface() */ @@ -335,7 +379,8 @@ QSGRenderNode::RenderState::~RenderState() /*! \fn const QMatrix4x4 *QSGRenderNode::RenderState::scissorRect() const - \return the current scissor rectangle when clipping is active. + \return the current scissor rectangle when clipping is active. x and y are + the bottom left coordinates. \note Be aware of the differences between graphics APIs: for some the scissor rect is only active when scissoring is enabled (for example, -- cgit v1.2.3 From ef2715251e1785e273873e4000ed08fd99962ab7 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 16 Aug 2019 09:54:03 +0200 Subject: Add missing scenegraph example docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I72e18136a26cdfb52f204ce7d0491d14411956a4 Reviewed-by: Christian Strømme --- .../doc/images/d3d11underqml-example.jpg | Bin 0 -> 79343 bytes .../d3d11underqml/doc/src/d3d11underqml.qdoc | 58 ++++++++ .../doc/images/metalunderqml-example.jpg | Bin 0 -> 55194 bytes .../metalunderqml/doc/src/metalunderqml.qdoc | 68 +++++++++ .../openglunderqml/doc/src/openglunderqml.qdoc | 5 + .../scenegraph/rendernode/customrenderitem.cpp | 4 + .../rendernode/doc/images/rendernode-example.jpg | Bin 0 -> 77210 bytes .../scenegraph/rendernode/doc/src/rendernode.qdoc | 163 +++++++++++++++++++++ examples/quick/scenegraph/rendernode/main.cpp | 2 + examples/quick/scenegraph/rendernode/main.qml | 8 + .../quick/scenegraph/rendernode/openglrenderer.cpp | 11 +- .../quick/scenegraph/rendernode/openglrenderer.h | 2 + 12 files changed, 320 insertions(+), 1 deletion(-) create mode 100644 examples/quick/scenegraph/d3d11underqml/doc/images/d3d11underqml-example.jpg create mode 100644 examples/quick/scenegraph/d3d11underqml/doc/src/d3d11underqml.qdoc create mode 100644 examples/quick/scenegraph/metalunderqml/doc/images/metalunderqml-example.jpg create mode 100644 examples/quick/scenegraph/metalunderqml/doc/src/metalunderqml.qdoc create mode 100644 examples/quick/scenegraph/rendernode/doc/images/rendernode-example.jpg create mode 100644 examples/quick/scenegraph/rendernode/doc/src/rendernode.qdoc diff --git a/examples/quick/scenegraph/d3d11underqml/doc/images/d3d11underqml-example.jpg b/examples/quick/scenegraph/d3d11underqml/doc/images/d3d11underqml-example.jpg new file mode 100644 index 0000000000..9f1e53ad61 Binary files /dev/null and b/examples/quick/scenegraph/d3d11underqml/doc/images/d3d11underqml-example.jpg differ diff --git a/examples/quick/scenegraph/d3d11underqml/doc/src/d3d11underqml.qdoc b/examples/quick/scenegraph/d3d11underqml/doc/src/d3d11underqml.qdoc new file mode 100644 index 0000000000..d7b60d3b81 --- /dev/null +++ b/examples/quick/scenegraph/d3d11underqml/doc/src/d3d11underqml.qdoc @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example scenegraph/d3d11underqml + \title Scene Graph - Direct3D 11 Under QML + \ingroup qtquickexamples + \brief Shows how to render directly with Direct3D 11 under a Qt Quick scene. + + \image d3d11underqml-example.jpg + + The Direct3D 11 Under QML example shows how an application can make use + of the \l QQuickWindow::beforeRendering() signal to draw custom + D3D11 content under a Qt Quick scene. This signal is emitted at + the start of every frame, before the scene graph starts its + rendering, thus any D3D11 draw calls that are made as a response + to this signal, will stack under the Qt Quick items. + + As an alternative, applications that wish to render D3D11 content + on top of the Qt Quick scene, can do so by connecting to the \l + QQuickWindow::afterRendering() signal. + + In this example, we will also see how it is possible to have + values that are exposed to QML which affect the D3D11 + rendering. We animate the threshold value using a NumberAnimation + in the QML file and this value is used by the HLSL shader + program that draws the squircles. + + The example is equivalent in most ways to the \l{Scene Graph - OpenGL Under + QML}{OpenGL Under QML} and \l{Scene Graph - Metal Under QML}{Metal Under + QML} examples, they all render the same custom content, just via different + native APIs. + + */ diff --git a/examples/quick/scenegraph/metalunderqml/doc/images/metalunderqml-example.jpg b/examples/quick/scenegraph/metalunderqml/doc/images/metalunderqml-example.jpg new file mode 100644 index 0000000000..98085773de Binary files /dev/null and b/examples/quick/scenegraph/metalunderqml/doc/images/metalunderqml-example.jpg differ diff --git a/examples/quick/scenegraph/metalunderqml/doc/src/metalunderqml.qdoc b/examples/quick/scenegraph/metalunderqml/doc/src/metalunderqml.qdoc new file mode 100644 index 0000000000..d499f47de3 --- /dev/null +++ b/examples/quick/scenegraph/metalunderqml/doc/src/metalunderqml.qdoc @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example scenegraph/metalunderqml + \title Scene Graph - Metal Under QML + \ingroup qtquickexamples + \brief Shows how to render directly with Metal under a Qt Quick scene. + + \image metalunderqml-example.jpg + + The Metal Under QML example shows how an application can make use + of the \l QQuickWindow::beforeRendering() and \l + QQuickWindow::beforeRenderPassRecording() signals to draw custom + Metal content under a Qt Quick scene. This signal is emitted at + the start of every frame, before the scene graph starts its + rendering, thus any Metal draw calls that are made as a response + to this signal, will stack under the Qt Quick items. There are two + signals, because the custom Metal commands are recorded onto the + same command buffer with the same render command encoder that the + scene graph uses. beforeRendering() on its own is not sufficient + for this because it gets emitted at the start of the frame, before + having an + \l{https://developer.apple.com/documentation/metal/mtlrendercommandencoder}{MTLRenderCommandEncoder} + available. By also connecting to beforeRenderPassRecording(), the + application can gain access to the necessary native objects. + + As an alternative, applications that wish to render Metal content + on top of the Qt Quick scene, can do so by connecting to the \l + QQuickWindow::afterRendering() and \l + QQuickWindow::afterRenderPassRecording() signals. + + In this example, we will also see how it is possible to have + values that are exposed to QML which affect the Metal + rendering. We animate the threshold value using a NumberAnimation + in the QML file and this value is used by the Metal shader + program that draws the squircles. + + The example is equivalent in most ways to the \l{Scene Graph - OpenGL Under + QML}{OpenGL Under QML} and \l{Scene Graph - Direct3D 11 Under QML}{Direct3D + 11 Under QML} examples, they all render the same custom content, just via + different native APIs. + + */ diff --git a/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc b/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc index 69a9d2ce4b..ed46b40420 100644 --- a/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc +++ b/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc @@ -50,6 +50,11 @@ in the QML file and this value is used by the OpenGL shader program that draws the squircles. + The example is equivalent in most ways to the \l{Scene Graph - Direct3D 11 Under + QML}{Direct3D 11 Under QML} and \l{Scene Graph - Metal Under QML}{Metal Under + QML} examples, they all render the same custom content, just via different + native APIs. + \snippet scenegraph/openglunderqml/squircle.h 2 First of all, we need an object we can expose to QML. This is a diff --git a/examples/quick/scenegraph/rendernode/customrenderitem.cpp b/examples/quick/scenegraph/rendernode/customrenderitem.cpp index 9dbe8d86a0..7ba9286afa 100644 --- a/examples/quick/scenegraph/rendernode/customrenderitem.cpp +++ b/examples/quick/scenegraph/rendernode/customrenderitem.cpp @@ -56,13 +56,16 @@ #include "d3d12renderer.h" #include "softwarerenderer.h" +//! [1] CustomRenderItem::CustomRenderItem(QQuickItem *parent) : QQuickItem(parent) { // Our item shows something so set the flag. setFlag(ItemHasContents); } +//! [1] +//! [2] QSGNode *CustomRenderItem::updatePaintNode(QSGNode *node, UpdatePaintNodeData *) { QSGRenderNode *n = static_cast(node); @@ -98,3 +101,4 @@ QSGNode *CustomRenderItem::updatePaintNode(QSGNode *node, UpdatePaintNodeData *) return n; } +//! [2] diff --git a/examples/quick/scenegraph/rendernode/doc/images/rendernode-example.jpg b/examples/quick/scenegraph/rendernode/doc/images/rendernode-example.jpg new file mode 100644 index 0000000000..cbb59b950d Binary files /dev/null and b/examples/quick/scenegraph/rendernode/doc/images/rendernode-example.jpg differ diff --git a/examples/quick/scenegraph/rendernode/doc/src/rendernode.qdoc b/examples/quick/scenegraph/rendernode/doc/src/rendernode.qdoc new file mode 100644 index 0000000000..e7864387cc --- /dev/null +++ b/examples/quick/scenegraph/rendernode/doc/src/rendernode.qdoc @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example scenegraph/rendernode + \title Scene Graph - Custom Rendering with QSGRenderNode + \ingroup qtquickexamples + \brief Shows how to integrate drawing via the native graphics API with the Qt Quick scene graph. + + \image rendernode-example.jpg + + \l QSGRenderNode allows integrating draw and other calls made directly via + the Qt Quick scene graph's underlying native graphics API (such as, Vulkan, + Metal, Direct 3D, or OpenGL). This example demonstrates implementing a + custom QQuickItem backed by a QSGRenderNode implementation, where the node + renders a triangle directly via the graphics API. The rest of the scene + (background, text, rectangles) are standard Qt Quick items. + + The custom item behaves like any other Qt Quick item, meaning it + participates and stacking and clipping as usual, which is a big difference + to the alternative approaches like having the custom rendering as an + overlay (connecting to \l QQuickWindow::afterRendering()) and underlay + (connecting to \l QQuickWindow::beforeRendering()) because those do not + offer the possibility of proper mixing of the custom content with the Qt + Quick scene. + + Another important feature is that QSGRenderNode can be helpful to preserve + performance, when compared to some of the alternatives. Going through \l + QQuickFramebufferObject allows creating a custom item similarly to what + this example does, but it does it by rendering the custom content in a + texture, and then drawing a textured quad with that texture. This can be + expensive on some systems due to the cost of texturing and blending. + QSGRenderNode avoids this since the native graphics calls are issued in + line with the draw calls for the scene graph's batches. + + All this comes at the cost of being more complex, and not necessarily being + suitable for all types of 3D content, in particular where vertices and + different depth would clash with the 2D content in the Qt Quick scene + graph's batches (those are better served by "flattening" into a 2D texture + via approaches like QQuickFramebufferObject). Therefore QSGRenderNode is + not always the right choice. It can however a good and powerful choice in + many cases. This is what the example demonstrates. + + Let's go through the most important parts of the code: + + \snippet scenegraph/rendernode/main.cpp 1 + + Our custom QML type is implemented in the class CustomRenderItem. + + \snippet scenegraph/rendernode/main.qml 2 + + The corresponding import in the QML document. + + \snippet scenegraph/rendernode/main.qml 3 + + The CustomRenderItem object. It is positioned to fill a big part of the + scene, covering its parent (the yellow rectangle; this will be used to + demonstrate clipping). The item will have its scale and rotation animated. + + \snippet scenegraph/rendernode/main.qml 4 + + Text items are used to show some helpful information, such as, the + active graphics API Qt Quick uses. + + \snippet scenegraph/rendernode/main.qml 5 + + Clicking the left mouse button is used to toggle clipping on the custom + item's parent item. By default this is done using scissoring (GL_SCISSOR_TEST + with OpenGL). A well-written QSGRenderNode implementation is expected to be + able to take this into account and enable scissor testing when the scene graph + indicates that it is necessary. + + The right mouse button is used to toggle an animation on the rotation of + the parent item. With clipping enabled, this demonstrates clipping via the + stencil buffer since a rectangular scissor is not appropriate when we need + to clip to a rotated rectangle shape. The scene graph fills up the stencil + buffer as necessary, the QSGRenderNode implementation just has to enable + stencil testing using the provided reference value. + + \snippet scenegraph/rendernode/customrenderitem.cpp 1 + + Moving on to the CustomRenderItem implementation. This is a visual item. + + \snippet scenegraph/rendernode/customrenderitem.cpp 2 + + The implementation of \l QQuickItem::updatePaintNode() creates (if not yet + done) and returns an instance of a suitable QSGRenderNode subclass. The + example supports multiple graphics APIs, and also the \c software backend. + + Let's look at the the render node for OpenGL (supporting both the + traditional, direct OpenGL-based scene graph, and also the modern, + abstracted variant using the RHI). For other graphics APIs, the concepts + and the outline of a QSGRenderNode implementation are the same. It is worth + noting that in some cases it will also be necessary to connect to a signal + like \l QQuickWindow::beforeRendering() to perform copy type of operations + (such as, vertex buffer uploads). This is not necessary for OpenGL, but it + is essential for Vulkan or Metal since there such operations cannot be + issued in render() as there is a renderpass being recorded when render() is + called. + + \snippet scenegraph/rendernode/openglrenderer.h 1 + + The main job is to provide implementations of the virtual QSGRenderNode functions. + + \snippet scenegraph/rendernode/openglrenderer.cpp 1 + + The pattern for safe graphics resource management is to do any cleanup in + \l{QSGRenderNode::releaseResources()}{releaseResources()}, while also + calling this from the destructor. + + \snippet scenegraph/rendernode/openglrenderer.cpp 2 + + The render() function initializes graphics resources (in this case, an + OpenGL shader program and a vertex buffer), if not yet done. It then + makes sure the necessary resources are bound and updates uniforms. + The transformation matrix and the opacity are provided by the scene graph + either via the \c state argument or base class functions. + + \snippet scenegraph/rendernode/openglrenderer.cpp 5 + + This render node is well-behaving since it basically renders in 2D, + respecting the item's geometry. This is not mandatory, but then flags() has + to return (or not return) the appropriate flags. + + \snippet scenegraph/rendernode/openglrenderer.cpp 3 + + After setting up vertex inputs, but before recording a draw call for our + triangle, it is important to set some state in order to integrate with the + rest of the scene correctly. Setting scissor and stencil as instructed by + \c state allows our item to render correctly even when there are one or + more clips in the parent chain. + + \snippet scenegraph/rendernode/openglrenderer.cpp 4 + + As shown above, we only really render in 2D (no depth), within the item's + geometry. changedStates() returns the flags corresponding to the OpenGL + states render() touches. + +*/ diff --git a/examples/quick/scenegraph/rendernode/main.cpp b/examples/quick/scenegraph/rendernode/main.cpp index 21419abfc9..146d787e50 100644 --- a/examples/quick/scenegraph/rendernode/main.cpp +++ b/examples/quick/scenegraph/rendernode/main.cpp @@ -58,7 +58,9 @@ int main(int argc, char **argv) { QGuiApplication app(argc, argv); +//! [1] qmlRegisterType("SceneGraphRendering", 2, 0, "CustomRenderItem"); +//! [1] QQuickView view; diff --git a/examples/quick/scenegraph/rendernode/main.qml b/examples/quick/scenegraph/rendernode/main.qml index 85060261c5..c89d6136c7 100644 --- a/examples/quick/scenegraph/rendernode/main.qml +++ b/examples/quick/scenegraph/rendernode/main.qml @@ -49,7 +49,9 @@ ****************************************************************************/ import QtQuick 2.8 +//! [2] import SceneGraphRendering 2.0 +//! [2] Item { Rectangle { @@ -60,6 +62,7 @@ Item { GradientStop { position: 1; color: "black" } } + //! [5] MouseArea { anchors.fill: parent acceptedButtons: Qt.LeftButton | Qt.RightButton @@ -73,6 +76,7 @@ Item { } } } + // ![5] Rectangle { id: clipper @@ -88,6 +92,7 @@ Item { running: false } + //! [3] CustomRenderItem { id: renderer width: bg.width - 20 @@ -102,6 +107,7 @@ Item { Translate { id: txIn; x: renderer.width / 2; y: renderer.height / 2 } ] } + //! [3] } SequentialAnimation { @@ -124,6 +130,7 @@ Item { loops: Animation.Infinite } + //! [4] Text { id: label anchors.bottom: parent.bottom @@ -146,6 +153,7 @@ Item { + "\nLeft click to toggle clipping to yellow rect" + "\nRight click to rotate (can be used to exercise stencil clip instead of scissor)" } + // ![4] } Text { diff --git a/examples/quick/scenegraph/rendernode/openglrenderer.cpp b/examples/quick/scenegraph/rendernode/openglrenderer.cpp index 5e6b9e3656..0633731617 100644 --- a/examples/quick/scenegraph/rendernode/openglrenderer.cpp +++ b/examples/quick/scenegraph/rendernode/openglrenderer.cpp @@ -57,6 +57,7 @@ #include #include +//! [1] OpenGLRenderNode::OpenGLRenderNode(QQuickItem *item) : m_item(item) { @@ -74,6 +75,7 @@ void OpenGLRenderNode::releaseResources() delete m_vbo; m_vbo = nullptr; } +//! [1] void OpenGLRenderNode::init() { @@ -121,19 +123,21 @@ void OpenGLRenderNode::init() m_vbo->release(); } +//! [2] void OpenGLRenderNode::render(const RenderState *state) { if (!m_program) init(); QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); - m_program->bind(); m_program->setUniformValue(m_matrixUniform, *state->projectionMatrix() * *matrix()); m_program->setUniformValue(m_opacityUniform, float(inheritedOpacity())); +//! [2] m_vbo->bind(); +//! [5] QPointF p0(m_item->width() - 1, m_item->height() - 1); QPointF p1(0, 0); QPointF p2(0, m_item->height() - 1); @@ -142,6 +146,7 @@ void OpenGLRenderNode::render(const RenderState *state) GLfloat(p1.x()), GLfloat(p1.y()), GLfloat(p2.x()), GLfloat(p2.y()) }; m_vbo->write(0, vertices, sizeof(vertices)); +//! [5] m_program->setAttributeBuffer(0, GL_FLOAT, 0, 2); m_program->setAttributeBuffer(1, GL_FLOAT, sizeof(vertices), 3); @@ -152,6 +157,7 @@ void OpenGLRenderNode::render(const RenderState *state) // (abstracted by RHI) OpenGL scenegraph. So set all the states that are // important to us. + //! [3] f->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); f->glEnable(GL_BLEND); @@ -170,8 +176,10 @@ void OpenGLRenderNode::render(const RenderState *state) } f->glDrawArrays(GL_TRIANGLES, 0, 3); + //! [3] } +//! [4] QSGRenderNode::StateFlags OpenGLRenderNode::changedStates() const { return BlendState | ScissorState | StencilState; @@ -186,5 +194,6 @@ QRectF OpenGLRenderNode::rect() const { return QRect(0, 0, m_item->width(), m_item->height()); } +//! [4] #endif // opengl diff --git a/examples/quick/scenegraph/rendernode/openglrenderer.h b/examples/quick/scenegraph/rendernode/openglrenderer.h index ac640405c5..8d2d3caad1 100644 --- a/examples/quick/scenegraph/rendernode/openglrenderer.h +++ b/examples/quick/scenegraph/rendernode/openglrenderer.h @@ -63,6 +63,7 @@ class QOpenGLBuffer; QT_END_NAMESPACE +//! [1] class OpenGLRenderNode : public QSGRenderNode { public: @@ -74,6 +75,7 @@ public: StateFlags changedStates() const override; RenderingFlags flags() const override; QRectF rect() const override; +//! [1] private: void init(); -- cgit v1.2.3 From 7dcdf3b7ae27cd26b84731941f5b1f380c5b3316 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 16 Aug 2019 14:21:15 +0200 Subject: rendernode example: Add support for Metal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plus clarify QQuickWindow::begin/endExternalCommands() in combination with QSGRenderNode in the docs. As the example demonstrates, calling these functions is not necessary within render() of a render node. Also fix an issue with resetting the scissor in the renderer after calling render() of a QSGRenderNode. Change-Id: If8c2dab38d62aa444266d37901f062a51e767f68 Reviewed-by: Christian Strømme --- .../scenegraph/rendernode/customrenderitem.cpp | 16 + .../scenegraph/rendernode/doc/src/rendernode.qdoc | 4 +- examples/quick/scenegraph/rendernode/main.qml | 1 + .../quick/scenegraph/rendernode/metalrenderer.h | 100 +++++++ .../quick/scenegraph/rendernode/metalrenderer.mm | 326 +++++++++++++++++++++ .../quick/scenegraph/rendernode/metalshader.frag | 28 ++ .../quick/scenegraph/rendernode/metalshader.vert | 31 ++ .../quick/scenegraph/rendernode/rendernode.pro | 6 + .../quick/scenegraph/rendernode/rendernode.qrc | 2 + src/quick/items/qquickwindow.cpp | 10 + src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp | 9 +- 11 files changed, 529 insertions(+), 4 deletions(-) create mode 100644 examples/quick/scenegraph/rendernode/metalrenderer.h create mode 100644 examples/quick/scenegraph/rendernode/metalrenderer.mm create mode 100644 examples/quick/scenegraph/rendernode/metalshader.frag create mode 100644 examples/quick/scenegraph/rendernode/metalshader.vert diff --git a/examples/quick/scenegraph/rendernode/customrenderitem.cpp b/examples/quick/scenegraph/rendernode/customrenderitem.cpp index 7ba9286afa..67a9cccfc6 100644 --- a/examples/quick/scenegraph/rendernode/customrenderitem.cpp +++ b/examples/quick/scenegraph/rendernode/customrenderitem.cpp @@ -53,6 +53,7 @@ #include #include "openglrenderer.h" +#include "metalrenderer.h" #include "d3d12renderer.h" #include "softwarerenderer.h" @@ -82,6 +83,18 @@ QSGNode *CustomRenderItem::updatePaintNode(QSGNode *node, UpdatePaintNodeData *) #endif break; + case QSGRendererInterface::MetalRhi: +#ifdef Q_OS_DARWIN + { + MetalRenderNode *metalNode = new MetalRenderNode(this); + n = metalNode; + metalNode->resourceBuilder()->setWindow(window()); + QObject::connect(window(), &QQuickWindow::beforeRendering, + metalNode->resourceBuilder(), &MetalRenderNodeResourceBuilder::build); + } +#endif + break; + case QSGRendererInterface::Direct3D12: // ### Qt 6: remove #if QT_CONFIG(d3d12) n = new D3D12RenderNode(this); @@ -102,3 +115,6 @@ QSGNode *CustomRenderItem::updatePaintNode(QSGNode *node, UpdatePaintNodeData *) return n; } //! [2] + +// This item does not support being moved between windows. If that is desired, +// itemChange() should be reimplemented as well. diff --git a/examples/quick/scenegraph/rendernode/doc/src/rendernode.qdoc b/examples/quick/scenegraph/rendernode/doc/src/rendernode.qdoc index e7864387cc..ba6551fddf 100644 --- a/examples/quick/scenegraph/rendernode/doc/src/rendernode.qdoc +++ b/examples/quick/scenegraph/rendernode/doc/src/rendernode.qdoc @@ -38,7 +38,9 @@ Metal, Direct 3D, or OpenGL). This example demonstrates implementing a custom QQuickItem backed by a QSGRenderNode implementation, where the node renders a triangle directly via the graphics API. The rest of the scene - (background, text, rectangles) are standard Qt Quick items. + (background, text, rectangles) are standard Qt Quick items. The example has + full support for OpenGL and Metal, as well as the software backend of Qt + Quick. The custom item behaves like any other Qt Quick item, meaning it participates and stacking and clipping as usual, which is a big difference diff --git a/examples/quick/scenegraph/rendernode/main.qml b/examples/quick/scenegraph/rendernode/main.qml index c89d6136c7..153a71e097 100644 --- a/examples/quick/scenegraph/rendernode/main.qml +++ b/examples/quick/scenegraph/rendernode/main.qml @@ -146,6 +146,7 @@ Item { case GraphicsInfo.Direct3D12: apiStr = "Direct3D 12 (direct)"; break; case GraphicsInfo.Software: apiStr = "Software (QPainter)"; break; case GraphicsInfo.OpenGLRhi: apiStr = "OpenGL (RHI)"; break; + case GraphicsInfo.MetalRhi: apiStr = "Metal (RHI)"; break; // the example has no other QSGRenderNode subclasses default: apiStr = ""; break; } diff --git a/examples/quick/scenegraph/rendernode/metalrenderer.h b/examples/quick/scenegraph/rendernode/metalrenderer.h new file mode 100644 index 0000000000..77c9892313 --- /dev/null +++ b/examples/quick/scenegraph/rendernode/metalrenderer.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, 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$ +** +****************************************************************************/ + +#ifndef METALRENDERER_H +#define METALRENDERER_H + +#include + +#ifdef Q_OS_DARWIN + +QT_BEGIN_NAMESPACE + +class QQuickItem; +class QQuickWindow; + +QT_END_NAMESPACE + +class MetalRenderNodeResourceBuilder : public QObject +{ + Q_OBJECT + +public: + void setWindow(QQuickWindow *w) { m_window = w; } + +public slots: + void build(); + +private: + QQuickWindow *m_window = nullptr; +}; + +class MetalRenderNode : public QSGRenderNode +{ +public: + MetalRenderNode(QQuickItem *item); + ~MetalRenderNode(); + + void render(const RenderState *state) override; + void releaseResources() override; + StateFlags changedStates() const override; + RenderingFlags flags() const override; + QRectF rect() const override; + + MetalRenderNodeResourceBuilder *resourceBuilder() { return &m_resourceBuilder; } + +private: + QQuickItem *m_item; + MetalRenderNodeResourceBuilder m_resourceBuilder; +}; + +#endif // Q_OS_DARWIN + +#endif diff --git a/examples/quick/scenegraph/rendernode/metalrenderer.mm b/examples/quick/scenegraph/rendernode/metalrenderer.mm new file mode 100644 index 0000000000..4cb973abee --- /dev/null +++ b/examples/quick/scenegraph/rendernode/metalrenderer.mm @@ -0,0 +1,326 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, 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$ +** +****************************************************************************/ + +#include "metalrenderer.h" +#include +#include + +#include + +using FuncAndLib = QPair, id >; + +const int MAX_FRAMES_IN_FLIGHT = 3; + +struct { + id dev = nil; + QByteArray vsSource; + FuncAndLib vs; + QByteArray fsSource; + FuncAndLib fs; + id vbuf[MAX_FRAMES_IN_FLIGHT]; + id ubuf[MAX_FRAMES_IN_FLIGHT]; + id stencilEnabledDsState = nil; + id pipeline = nil; +} g; + +static FuncAndLib compileShaderFromSource(const QByteArray &src, const QByteArray &entryPoint) +{ + FuncAndLib fl; + + NSString *srcstr = [NSString stringWithUTF8String: src.constData()]; + MTLCompileOptions *opts = [[MTLCompileOptions alloc] init]; + opts.languageVersion = MTLLanguageVersion1_2; + NSError *err = nil; + fl.second = [g.dev newLibraryWithSource: srcstr options: opts error: &err]; + [opts release]; + // srcstr is autoreleased + + if (err) { + const QString msg = QString::fromNSString(err.localizedDescription); + qFatal("%s", qPrintable(msg)); + return fl; + } + + NSString *name = [NSString stringWithUTF8String: entryPoint.constData()]; + fl.first = [fl.second newFunctionWithName: name]; + [name release]; + + return fl; +} + +const int VERTEX_SIZE = 6 * sizeof(float); + +static float colors[] = { + 1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 1.0f +}; + +void MetalRenderNodeResourceBuilder::build() +{ + if (!g.dev) { + QSGRendererInterface *rif = m_window->rendererInterface(); + Q_ASSERT(rif->graphicsApi() == QSGRendererInterface::MetalRhi); + + g.dev = (id) rif->getResource(m_window, QSGRendererInterface::DeviceResource); + Q_ASSERT(g.dev); + } + + if (g.vsSource.isEmpty()) { + const QString filename = QLatin1String(":/scenegraph/rendernode/metalshader.vert"); + QFile f(filename); + if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) + qFatal("Failed to read shader %s", qPrintable(filename)); + g.vsSource = f.readAll(); + g.vs = compileShaderFromSource(g.vsSource, QByteArrayLiteral("main0")); + } + + if (g.fsSource.isEmpty()) { + const QString filename = QLatin1String(":/scenegraph/rendernode/metalshader.frag"); + QFile f(filename); + if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) + qFatal("Failed to read shader %s", qPrintable(filename)); + g.fsSource = f.readAll(); + g.fs = compileShaderFromSource(g.fsSource, QByteArrayLiteral("main0")); + } + + const int framesInFlight = m_window->graphicsStateInfo()->framesInFlight; + + // For simplicity's sake we use shared mode (something like host visible + + // host coherent) for everything. + + for (int i = 0; i < framesInFlight; ++i) { + // Have multiple versions for vertex too since we'll just memcpy new + // vertices based on item width and height on every render(). This could + // be optimized further however. + if (!g.vbuf[i]) { + g.vbuf[i] = [g.dev newBufferWithLength: VERTEX_SIZE + sizeof(colors) options: MTLResourceStorageModeShared]; + char *p = (char *) [g.vbuf[i] contents]; + memcpy(p + VERTEX_SIZE, colors, sizeof(colors)); + } + + if (!g.ubuf[i]) + g.ubuf[i] = [g.dev newBufferWithLength: 256 options: MTLResourceStorageModeShared]; + } + + if (!g.stencilEnabledDsState) { + MTLDepthStencilDescriptor *dsDesc = [[MTLDepthStencilDescriptor alloc] init]; + dsDesc.frontFaceStencil = [[MTLStencilDescriptor alloc] init]; + dsDesc.frontFaceStencil.stencilFailureOperation = MTLStencilOperationKeep; + dsDesc.frontFaceStencil.depthFailureOperation = MTLStencilOperationKeep; + dsDesc.frontFaceStencil.depthStencilPassOperation = MTLStencilOperationKeep; + dsDesc.frontFaceStencil.stencilCompareFunction = MTLCompareFunctionEqual; + dsDesc.frontFaceStencil.readMask = 0xFF; + dsDesc.frontFaceStencil.writeMask = 0xFF; + + dsDesc.backFaceStencil = [[MTLStencilDescriptor alloc] init]; + dsDesc.backFaceStencil.stencilFailureOperation = MTLStencilOperationKeep; + dsDesc.backFaceStencil.depthFailureOperation = MTLStencilOperationKeep; + dsDesc.backFaceStencil.depthStencilPassOperation = MTLStencilOperationKeep; + dsDesc.backFaceStencil.stencilCompareFunction = MTLCompareFunctionEqual; + dsDesc.backFaceStencil.readMask = 0xFF; + dsDesc.backFaceStencil.writeMask = 0xFF; + + g.stencilEnabledDsState = [g.dev newDepthStencilStateWithDescriptor: dsDesc]; + [dsDesc release]; + } + + if (!g.pipeline) { + MTLVertexDescriptor *inputLayout = [MTLVertexDescriptor vertexDescriptor]; + inputLayout.attributes[0].format = MTLVertexFormatFloat2; + inputLayout.attributes[0].offset = 0; + inputLayout.attributes[0].bufferIndex = 1; // ubuf is 0, vbuf is 1 and 2 + inputLayout.attributes[1].format = MTLVertexFormatFloat3; + inputLayout.attributes[1].offset = 0; + inputLayout.attributes[1].bufferIndex = 2; + inputLayout.layouts[1].stride = 2 * sizeof(float); + inputLayout.layouts[2].stride = 3 * sizeof(float); + + MTLRenderPipelineDescriptor *rpDesc = [[MTLRenderPipelineDescriptor alloc] init]; + rpDesc.vertexDescriptor = inputLayout; + + rpDesc.vertexFunction = g.vs.first; + rpDesc.fragmentFunction = g.fs.first; + + rpDesc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm; + rpDesc.colorAttachments[0].blendingEnabled = true; + rpDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorOne; + rpDesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne; + rpDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha; + rpDesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha; + + if (g.dev.depth24Stencil8PixelFormatSupported) { + rpDesc.depthAttachmentPixelFormat = MTLPixelFormatDepth24Unorm_Stencil8; + rpDesc.stencilAttachmentPixelFormat = MTLPixelFormatDepth24Unorm_Stencil8; + } else { + rpDesc.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8; + rpDesc.stencilAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8; + } + + NSError *err = nil; + g.pipeline = [g.dev newRenderPipelineStateWithDescriptor: rpDesc error: &err]; + if (!g.pipeline) { + const QString msg = QString::fromNSString(err.localizedDescription); + qFatal("Failed to create render pipeline state: %s", qPrintable(msg)); + } + [rpDesc release]; + } +} + +MetalRenderNode::MetalRenderNode(QQuickItem *item) + : m_item(item) +{ + g.vs.first = g.fs.first = nil; + g.vs.second = g.fs.second = nil; + + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { + g.vbuf[i] = nil; + g.ubuf[i] = nil; + } +} + +MetalRenderNode::~MetalRenderNode() +{ + releaseResources(); +} + +void MetalRenderNode::releaseResources() +{ + [g.stencilEnabledDsState release]; + g.stencilEnabledDsState = nil; + + [g.pipeline release]; + g.pipeline = nil; + + [g.vs.first release]; + [g.vs.second release]; + + [g.fs.first release]; + [g.fs.second release]; + + g.vs.first = g.fs.first = nil; + g.vs.second = g.fs.second = nil; + + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { + [g.vbuf[i] release]; + g.vbuf[i] = nil; + [g.ubuf[i] release]; + g.ubuf[i] = nil; + } +} + +void MetalRenderNode::render(const RenderState *state) +{ + QQuickWindow *window = m_item->window(); + const QQuickWindow::GraphicsStateInfo *stateInfo = window->graphicsStateInfo(); + id vbuf = g.vbuf[stateInfo->currentFrameSlot]; + id ubuf = g.ubuf[stateInfo->currentFrameSlot]; + + QPointF p0(m_item->width() - 1, m_item->height() - 1); + QPointF p1(0, 0); + QPointF p2(0, m_item->height() - 1); + + float vertices[6] = { float(p0.x()), float(p0.y()), + float(p1.x()), float(p1.y()), + float(p2.x()), float(p2.y()) }; + char *p = (char *) [vbuf contents]; + memcpy(p, vertices, VERTEX_SIZE); + + const QMatrix4x4 mvp = *state->projectionMatrix() * *matrix(); + const float opacity = inheritedOpacity(); + + p = (char *) [ubuf contents]; + memcpy(p, mvp.constData(), 64); + memcpy(p + 64, &opacity, 4); + + QSGRendererInterface *rif = window->rendererInterface(); + id encoder = (id) rif->getResource( + window, QSGRendererInterface::CommandEncoderResource); + Q_ASSERT(encoder); + + [encoder setVertexBuffer: vbuf offset: 0 atIndex: 1]; + [encoder setVertexBuffer: vbuf offset: VERTEX_SIZE atIndex: 2]; + + [encoder setVertexBuffer: ubuf offset: 0 atIndex: 0]; + [encoder setFragmentBuffer: ubuf offset: 0 atIndex: 0]; + + // Clip support. + if (state->scissorEnabled()) { + const QRect r = state->scissorRect(); // bottom-up + MTLScissorRect s; + s.x = r.x(); + s.y = (window->height() * window->effectiveDevicePixelRatio()) - (r.y() + r.height()); + s.width = r.width(); + s.height = r.height(); + [encoder setScissorRect: s]; + } + if (state->stencilEnabled()) { + [encoder setDepthStencilState: g.stencilEnabledDsState]; + [encoder setStencilReferenceValue: state->stencilValue()]; + } + + [encoder setRenderPipelineState: g.pipeline]; + [encoder drawPrimitives: MTLPrimitiveTypeTriangle vertexStart: 0 vertexCount: 3 instanceCount: 1 baseInstance: 0]; +} + +QSGRenderNode::StateFlags MetalRenderNode::changedStates() const +{ + return BlendState | ScissorState | StencilState; +} + +QSGRenderNode::RenderingFlags MetalRenderNode::flags() const +{ + return BoundedRectRendering | DepthAwareRendering; +} + +QRectF MetalRenderNode::rect() const +{ + return QRect(0, 0, m_item->width(), m_item->height()); +} diff --git a/examples/quick/scenegraph/rendernode/metalshader.frag b/examples/quick/scenegraph/rendernode/metalshader.frag new file mode 100644 index 0000000000..907faa537f --- /dev/null +++ b/examples/quick/scenegraph/rendernode/metalshader.frag @@ -0,0 +1,28 @@ +#include +#include + +using namespace metal; + +struct buf +{ + float4x4 matrix; + float opacity; +}; + +struct main0_out +{ + float4 fragColor [[color(0)]]; +}; + +struct main0_in +{ + float4 v_color [[user(locn0)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], constant buf& ubuf [[buffer(0)]]) +{ + main0_out out = {}; + out.fragColor = in.v_color * ubuf.opacity; + return out; +} + diff --git a/examples/quick/scenegraph/rendernode/metalshader.vert b/examples/quick/scenegraph/rendernode/metalshader.vert new file mode 100644 index 0000000000..12b721f524 --- /dev/null +++ b/examples/quick/scenegraph/rendernode/metalshader.vert @@ -0,0 +1,31 @@ +#include +#include + +using namespace metal; + +struct buf +{ + float4x4 matrix; + float opacity; +}; + +struct main0_out +{ + float4 v_color [[user(locn0)]]; + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float4 pos [[attribute(0)]]; + float4 color [[attribute(1)]]; +}; + +vertex main0_out main0(main0_in in [[stage_in]], constant buf& ubuf [[buffer(0)]]) +{ + main0_out out = {}; + out.v_color = in.color; + out.gl_Position = ubuf.matrix * in.pos; + return out; +} + diff --git a/examples/quick/scenegraph/rendernode/rendernode.pro b/examples/quick/scenegraph/rendernode/rendernode.pro index 76e498042b..897b0b1f08 100644 --- a/examples/quick/scenegraph/rendernode/rendernode.pro +++ b/examples/quick/scenegraph/rendernode/rendernode.pro @@ -22,3 +22,9 @@ qtConfig(d3d12) { SOURCES += d3d12renderer.cpp LIBS += -ld3d12 } + +macos { + HEADERS += metalrenderer.h + SOURCES += metalrenderer.mm + LIBS += -framework Metal -framework AppKit +} diff --git a/examples/quick/scenegraph/rendernode/rendernode.qrc b/examples/quick/scenegraph/rendernode/rendernode.qrc index 049adcf8a6..5907eab62c 100644 --- a/examples/quick/scenegraph/rendernode/rendernode.qrc +++ b/examples/quick/scenegraph/rendernode/rendernode.qrc @@ -3,5 +3,7 @@ main.qml shader_vert.cso shader_frag.cso + metalshader.vert + metalshader.frag diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 88a731b229..8b5e2a012a 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -4666,6 +4666,11 @@ const QQuickWindow::GraphicsStateInfo *QQuickWindow::graphicsStateInfo() beginExternalCommands() and endExternalCommands() together provide a replacement for resetOpenGLState(). + Calling this function and endExternalCommands() is not necessary within the + \l{QSGRenderNode::render()}{render()} implementation of a QSGRenderNode + because the scene graph performs the necessary steps implicitly for render + nodes. + \note This function has no effect when the scene graph is using OpenGL directly and the RHI graphics abstraction layer is not in use. Refer to resetOpenGLState() in that case. @@ -4704,6 +4709,11 @@ void QQuickWindow::beginExternalCommands() beginExternalCommands() and endExternalCommands() together provide a replacement for resetOpenGLState(). + Calling this function and beginExternalCommands() is not necessary within the + \l{QSGRenderNode::render()}{render()} implementation of a QSGRenderNode + because the scene graph performs the necessary steps implicitly for render + nodes. + \note This function has no effect when the scene graph is using OpenGL directly and the RHI graphics abstraction layer is not in use. Refer to resetOpenGLState() in that case. diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index 293cc4cb6b..2441e14fda 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -4563,11 +4563,14 @@ void Renderer::renderRhiRenderNode(const Batch *batch) // split prepare-render ( rd->m_matrix = nullptr; rd->m_clip_list = nullptr; - if (changes & QSGRenderNode::ViewportState) + if ((changes & QSGRenderNode::ViewportState) + || (changes & QSGRenderNode::ScissorState)) + { + // Reset both flags if either is reported as changed, since with the rhi + // it could be setViewport() that will record the resetting of the scissor. m_pstate.viewportSet = false; - - if (changes & QSGRenderNode::ScissorState) m_pstate.scissorSet = false; + } // Do not bother with RenderTargetState. Where applicable, endExternal() // ensures the correct target is rebound. For others (like Vulkan) it makes -- cgit v1.2.3 From db9bf0be1cc37ec0496765d21973c8db487f9a9d Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 5 Aug 2019 19:42:23 +0200 Subject: Remove an unused event type in the threaded render loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I505ba09d6a0144f18bf29cda2f549c8b69ada1a5 Reviewed-by: Christian Strømme --- src/plugins/scenegraph/d3d12/qsgd3d12threadedrenderloop.cpp | 12 ------------ .../adaptations/software/qsgsoftwarethreadedrenderloop.cpp | 11 ----------- src/quick/scenegraph/qsgthreadedrenderloop.cpp | 11 ----------- 3 files changed, 34 deletions(-) diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12threadedrenderloop.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12threadedrenderloop.cpp index 120a84566f..f505df1e5a 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12threadedrenderloop.cpp +++ b/src/plugins/scenegraph/d3d12/qsgd3d12threadedrenderloop.cpp @@ -121,10 +121,6 @@ const QEvent::Type WM_Obscure = QEvent::Type(QEvent::User + 1); // Passed from the RL to RT when GUI has been locked, waiting for sync. const QEvent::Type WM_RequestSync = QEvent::Type(QEvent::User + 2); -// Passed by the RT to itself to trigger another render pass. This is typically -// a result of QQuickWindow::update(). -const QEvent::Type WM_RequestRepaint = QEvent::Type(QEvent::User + 3); - // Passed by the RL to the RT to maybe release resource if no windows are // rendering. const QEvent::Type WM_TryRelease = QEvent::Type(QEvent::User + 4); @@ -436,14 +432,6 @@ bool QSGD3D12RenderThread::event(QEvent *e) return true; } - case WM_RequestRepaint: - if (Q_UNLIKELY(debug_loop())) - qDebug("RT - WM_RequestPaint"); - // When GUI posts this event, it is followed by a polishAndSync, so we - // must not exit the event loop yet. - pendingUpdate |= RepaintRequest; - break; - default: break; } diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp index f8973af2fb..2d4dcd928d 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp @@ -69,10 +69,6 @@ const QEvent::Type WM_Obscure = QEvent::Type(QEvent::User + 1); // Passed from the RL to RT when GUI has been locked, waiting for sync. const QEvent::Type WM_RequestSync = QEvent::Type(QEvent::User + 2); -// Passed by the RT to itself to trigger another render pass. This is typically -// a result of QQuickWindow::update(). -const QEvent::Type WM_RequestRepaint = QEvent::Type(QEvent::User + 3); - // Passed by the RL to the RT to maybe release resource if no windows are // rendering. const QEvent::Type WM_TryRelease = QEvent::Type(QEvent::User + 4); @@ -353,13 +349,6 @@ bool QSGSoftwareRenderThread::event(QEvent *e) return true; } - case WM_RequestRepaint: - qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_RequestPaint"); - // When GUI posts this event, it is followed by a polishAndSync, so we - // must not exit the event loop yet. - pendingUpdate |= RepaintRequest; - break; - default: break; } diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index d1258cf903..9e34a2b201 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -147,10 +147,6 @@ const QEvent::Type WM_Obscure = QEvent::Type(QEvent::User + 1); // (updatePaintNode()) const QEvent::Type WM_RequestSync = QEvent::Type(QEvent::User + 2); -// Passed by the RT to itself to trigger another render pass. This is -// typically a result of QQuickWindow::update(). -const QEvent::Type WM_RequestRepaint = QEvent::Type(QEvent::User + 3); - // Passed by the RL to the RT to free up maybe release SG and GL contexts // if no windows are rendering. const QEvent::Type WM_TryRelease = QEvent::Type(QEvent::User + 4); @@ -510,13 +506,6 @@ bool QSGRenderThread::event(QEvent *e) return true; } - case WM_RequestRepaint: - qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "WM_RequestPaint"); - // When GUI posts this event, it is followed by a polishAndSync, so we mustn't - // exit the event loop yet. - pendingUpdate |= RepaintRequest; - break; - default: break; } -- cgit v1.2.3 From c763c5bbe6d0d3cf033fdae48eae068962e95a5f Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Fri, 16 Aug 2019 16:26:45 +0200 Subject: qmlplugindump: Handle types reexported by QtQuick Now that our own types are not registered with qmlRegisterType() anymore, we can use QQmlType::module to decide whether a type should be included in the qmltypes file. We include types with no module, to support existing user code which still calls qmlRegisterType(). Change-Id: Iee0a132bf5b3ddcdfc222ab4b2d37a1f05b1851d Reviewed-by: Ulf Hermann --- tools/qmlplugindump/main.cpp | 133 +++++++++++++++++++++++-------------------- 1 file changed, 72 insertions(+), 61 deletions(-) diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp index 464f3e8a6b..f0ed1f8ebe 100644 --- a/tools/qmlplugindump/main.cpp +++ b/tools/qmlplugindump/main.cpp @@ -100,21 +100,45 @@ static QString enquote(const QString &string) .replace(QLatin1Char('"'),QLatin1String("\\\""))); } -void collectReachableMetaObjects(const QMetaObject *meta, QSet *metas, bool extended = false) +struct QmlVersionInfo { + QString pluginImportUri; + int majorVersion; + int minorVersion; +}; + +static bool matchingImportUri(const QQmlType &ty, const QmlVersionInfo& versionInfo) { + return (versionInfo.pluginImportUri == ty.module() + && (ty.majorVersion() == versionInfo.majorVersion || ty.majorVersion() == -1)) + || ty.module().isEmpty(); +} + +void collectReachableMetaObjects(const QMetaObject *meta, QSet *metas, const QmlVersionInfo &info, bool extended = false, bool alreadyChangedModule = false) +{ + auto ty = QQmlMetaType::qmlType(meta); if (! meta || metas->contains(meta)) return; - // dynamic meta objects can break things badly - // but extended types are usually fine - const QMetaObjectPrivate *mop = reinterpret_cast(meta->d.data); - if (extended || !(mop->flags & DynamicMetaObject)) - metas->insert(meta); + if (matchingImportUri(ty, info)) { + if (!alreadyChangedModule) { + // dynamic meta objects can break things badly + // but extended types are usually fine + const QMetaObjectPrivate *mop = reinterpret_cast(meta->d.data); + if (extended || !(mop->flags & DynamicMetaObject)) + metas->insert(meta); + } else if (!ty.module().isEmpty()) { // empty module (e.g. from an attached property) would cause a (false) match; do not warn about them + qWarning() << "Circular module dependency cannot be expressed in plugin.qmltypes file" + << "Object was:" << meta->className() + << ty.module() << info.pluginImportUri; + } + } else if (!ty.module().isEmpty()) { + alreadyChangedModule = true; + } - collectReachableMetaObjects(meta->superClass(), metas); + collectReachableMetaObjects(meta->superClass(), metas, info, /*extended=*/ false, alreadyChangedModule); } -void collectReachableMetaObjects(QObject *object, QSet *metas) +void collectReachableMetaObjects(QObject *object, QSet *metas, const QmlVersionInfo &info) { if (! object) return; @@ -122,7 +146,7 @@ void collectReachableMetaObjects(QObject *object, QSet *met const QMetaObject *meta = object->metaObject(); if (verbose) std::cerr << "Processing object " << qPrintable( meta->className() ) << std::endl; - collectReachableMetaObjects(meta, metas); + collectReachableMetaObjects(meta, metas, info); for (int index = 0; index < meta->propertyCount(); ++index) { QMetaProperty prop = meta->property(index); @@ -135,17 +159,18 @@ void collectReachableMetaObjects(QObject *object, QSet *met // accessing a member of oo is going to cause a segmentation fault QObject *oo = QQmlMetaType::toQObject(prop.read(object)); if (oo && !metas->contains(oo->metaObject())) - collectReachableMetaObjects(oo, metas); + collectReachableMetaObjects(oo, metas, info); currentProperty.clear(); } } } -void collectReachableMetaObjects(QQmlEnginePrivate *engine, const QQmlType &ty, QSet *metas) +void collectReachableMetaObjects(QQmlEnginePrivate *engine, const QQmlType &ty, QSet *metas, const QmlVersionInfo& info) { - collectReachableMetaObjects(ty.baseMetaObject(), metas, ty.isExtendedType()); - if (ty.attachedPropertiesType(engine)) - collectReachableMetaObjects(ty.attachedPropertiesType(engine), metas); + collectReachableMetaObjects(ty.baseMetaObject(), metas, info, ty.isExtendedType()); + if (ty.attachedPropertiesType(engine) && matchingImportUri(ty, info)) { + collectReachableMetaObjects(ty.attachedPropertiesType(engine), metas, info); + } } /* We want to add the MetaObject for 'Qt' to the list, this is a @@ -205,13 +230,13 @@ QByteArray convertToId(const QMetaObject *mo) // Collect all metaobjects for types registered with qmlRegisterType() without parameters void collectReachableMetaObjectsWithoutQmlName(QQmlEnginePrivate *engine, QSet& metas, - QMap> &compositeTypes) { + QMap> &compositeTypes, const QmlVersionInfo &info) { const auto qmlAllTypes = QQmlMetaType::qmlAllTypes(); for (const QQmlType &ty : qmlAllTypes) { if (!metas.contains(ty.baseMetaObject())) { if (!ty.isComposite()) { - collectReachableMetaObjects(engine, ty, &metas); - } else { + collectReachableMetaObjects(engine, ty, &metas, info); + } else if (matchingImportUri(ty, info)) { compositeTypes[ty.elementName()].insert(ty); } } @@ -222,20 +247,24 @@ QSet collectReachableMetaObjects(QQmlEngine *engine, QSet &noncreatables, QSet &singletons, QMap> &compositeTypes, - const QList &skip = QList()) + const QmlVersionInfo &info, + const QList &skip = QList() + ) { QSet metas; metas.insert(FriendlyQObject::qtMeta()); const auto qmlTypes = QQmlMetaType::qmlTypes(); for (const QQmlType &ty : qmlTypes) { + if (!matchingImportUri(ty,info)) + continue; if (!ty.isCreatable()) noncreatables.insert(ty.baseMetaObject()); if (ty.isSingleton()) singletons.insert(ty.baseMetaObject()); if (!ty.isComposite()) { qmlTypesByCppName[ty.baseMetaObject()->className()].insert(ty); - collectReachableMetaObjects(QQmlEnginePrivate::get(engine), ty, &metas); + collectReachableMetaObjects(QQmlEnginePrivate::get(engine), ty, &metas, info); } else { compositeTypes[ty.elementName()].insert(ty); } @@ -245,6 +274,8 @@ QSet collectReachableMetaObjects(QQmlEngine *engine, // find even more QMetaObjects by instantiating QML types and running // over the instances for (const QQmlType &ty : qmlTypes) { + if (!matchingImportUri(ty, info)) + continue; if (skip.contains(ty)) continue; if (ty.isExtendedType()) @@ -274,7 +305,7 @@ QSet collectReachableMetaObjects(QQmlEngine *engine, if (verbose) std::cerr << "Trying to get singleton for " << qPrintable(tyName) << " (" << qPrintable( siinfo->typeName ) << ")" << std::endl; - collectReachableMetaObjects(object, &metas); + collectReachableMetaObjects(object, &metas, info); object = QQmlEnginePrivate::get(engine)->singletonInstance(ty); } else { inObjectInstantiation.clear(); @@ -293,7 +324,7 @@ QSet collectReachableMetaObjects(QQmlEngine *engine, if (verbose) std::cerr << "Got " << qPrintable( tyName ) << " (" << qPrintable( QString::fromUtf8(ty.typeName()) ) << ")" << std::endl; - collectReachableMetaObjects(object, &metas); + collectReachableMetaObjects(object, &metas, info); object->deleteLater(); } else { std::cerr << "Could not create " << qPrintable(tyName) << std::endl; @@ -301,7 +332,7 @@ QSet collectReachableMetaObjects(QQmlEngine *engine, } } - collectReachableMetaObjectsWithoutQmlName(QQmlEnginePrivate::get(engine), metas, compositeTypes); + collectReachableMetaObjectsWithoutQmlName(QQmlEnginePrivate::get(engine), metas, compositeTypes, info); return metas; } @@ -1186,11 +1217,7 @@ int main(int argc, char *argv[]) QSet uncreatableMetas; QSet singletonMetas; QMap> defaultCompositeTypes; - QSet defaultReachable = collectReachableMetaObjects(&engine, uncreatableMetas, singletonMetas, defaultCompositeTypes); - QList defaultTypes = QQmlMetaType::qmlTypes(); - // add some otherwise unreachable QMetaObjects - defaultReachable.insert(&QQuickMouseEvent::staticMetaObject); // QQuickKeyEvent, QQuickPinchEvent, QQuickDropEvent are not exported QSet defaultReachableNames; @@ -1200,35 +1227,25 @@ int main(int argc, char *argv[]) // composite types we want to dump information of QMap> compositeTypes; + int majorVersion = qtQmlMajorVersion, minorVersion = qtQmlMinorVersion; if (action == Builtins) { - for (const QMetaObject *m : qAsConst(defaultReachable)) { - if (m->className() == QLatin1String("Qt")) { - metas.insert(m); - break; - } - } - } else if (pluginImportUri == QLatin1String("QtQml")) { - bool ok = false; - const uint major = pluginImportVersion.splitRef('.').at(0).toUInt(&ok, 10); - if (!ok) { - std::cerr << "Malformed version string \""<< qPrintable(pluginImportVersion) << "\"." - << std::endl; - return EXIT_INVALIDARGUMENTS; - } - if (major != qtQmlMajorVersion) { - std::cerr << "Unsupported version \"" << qPrintable(pluginImportVersion) - << "\": Major version number must be \"" << qtQmlMajorVersion << "\"." - << std::endl; - return EXIT_INVALIDARGUMENTS; - } - metas = defaultReachable; - for (const QMetaObject *m : qAsConst(defaultReachable)) { - if (m->className() == QLatin1String("Qt")) { - metas.remove(m); - break; - } - } + QSet builtins = collectReachableMetaObjects(&engine, uncreatableMetas, singletonMetas, defaultCompositeTypes, {QLatin1String("Qt"), majorVersion, minorVersion}); + Q_ASSERT(builtins.size() == 1); + metas.insert(*builtins.begin()); } else { + auto versionSplitted = pluginImportVersion.split("."); + bool ok = versionSplitted.size() == 2; + if (!ok) + qCritical("Invalid version number"); + else { + majorVersion = versionSplitted.at(0).toInt(&ok); + if (!ok) + qCritical("Invalid major version"); + minorVersion = versionSplitted.at(1).toInt(&ok); + if (!ok) + qCritical("Invalid minor version"); + } + QList defaultTypes = QQmlMetaType::qmlTypes(); // find a valid QtQuick import QByteArray importCode; QQmlType qtObjectType = QQmlMetaType::qmlType(&QObject::staticMetaObject); @@ -1273,8 +1290,7 @@ int main(int argc, char *argv[]) } } - QSet candidates = collectReachableMetaObjects(&engine, uncreatableMetas, singletonMetas, compositeTypes, defaultTypes); - candidates.subtract(defaultReachable); + QSet candidates = collectReachableMetaObjects(&engine, uncreatableMetas, singletonMetas, compositeTypes, {pluginImportUri, majorVersion, minorVersion}, defaultTypes); for (QString iter: compositeTypes.keys()) { if (defaultCompositeTypes.contains(iter)) { @@ -1284,13 +1300,8 @@ int main(int argc, char *argv[]) } } - // Also eliminate meta objects with the same classname. - // This is required because extended objects seem not to share - // a single meta object instance. - for (const QMetaObject *mo : qAsConst(defaultReachable)) - defaultReachableNames.insert(QByteArray(mo->className())); for (const QMetaObject *mo : qAsConst(candidates)) { - if (!defaultReachableNames.contains(mo->className())) + if (mo->className() != QLatin1String("Qt")) metas.insert(mo); } } -- cgit v1.2.3 From 7919751e999d68d4b4e9dae37493d607e7759105 Mon Sep 17 00:00:00 2001 From: Aleix Pol Date: Sat, 20 Jul 2019 13:46:36 +0200 Subject: Improve error message when setting to a property with unknown type At the moment we were being told that the types were incompatible but the truth was we were comparing to nullptr. This patch makes it apparent that the assigning broke because the type comparison never happened. Change-Id: I29728eedeee13c3bc9389213735df142f56e9c34 Reviewed-by: Fabian Kosmale Reviewed-by: Ulf Hermann --- src/qml/qml/qqmlpropertyvalidator.cpp | 18 +++++++++++------- .../qqmllanguage/data/propertyUnknownType.errors.txt | 1 + .../auto/qml/qqmllanguage/data/propertyUnknownType.qml | 4 ++++ tests/auto/qml/qqmllanguage/testtypes.cpp | 1 + tests/auto/qml/qqmllanguage/testtypes.h | 13 +++++++++++++ tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 3 ++- 6 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 tests/auto/qml/qqmllanguage/data/propertyUnknownType.errors.txt create mode 100644 tests/auto/qml/qqmllanguage/data/propertyUnknownType.qml diff --git a/src/qml/qml/qqmlpropertyvalidator.cpp b/src/qml/qml/qqmlpropertyvalidator.cpp index 71964aca64..7dbcbe986b 100644 --- a/src/qml/qml/qqmlpropertyvalidator.cpp +++ b/src/qml/qml/qqmlpropertyvalidator.cpp @@ -711,21 +711,25 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateObjectBinding(QQmlPrope // Using -1 for the minor version ensures that we get the raw metaObject. QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(property->propType(), -1); - // Will be true if the assigned type inherits propertyMetaObject - bool isAssignable = false; - // Determine isAssignable value if (propertyMetaObject) { + // Will be true if the assigned type inherits propertyMetaObject + // Determine isAssignable value + bool isAssignable = false; QQmlPropertyCache *c = propertyCaches.at(binding->value.objectIndex); while (c && !isAssignable) { isAssignable |= c == propertyMetaObject; c = c->parent(); } - } - if (!isAssignable) { - return qQmlCompileError(binding->valueLocation, tr("Cannot assign object of type \"%1\" to property of type \"%2\" as the former is neither the same as the latter nor a sub-class of it.") - .arg(stringAt(compilationUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex)).arg(QLatin1String(QMetaType::typeName(property->propType())))); + if (!isAssignable) { + return qQmlCompileError(binding->valueLocation, tr("Cannot assign object of type \"%1\" to property of type \"%2\" as the former is neither the same as the latter nor a sub-class of it.") + .arg(stringAt(compilationUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex)).arg(QLatin1String(QMetaType::typeName(property->propType())))); + } + } else { + return qQmlCompileError(binding->valueLocation, tr("Cannot assign to property of unknown type \"%1\".") + .arg(QLatin1String(QMetaType::typeName(property->propType())))); } + } return noError; } diff --git a/tests/auto/qml/qqmllanguage/data/propertyUnknownType.errors.txt b/tests/auto/qml/qqmllanguage/data/propertyUnknownType.errors.txt new file mode 100644 index 0000000000..1655f9264a --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/propertyUnknownType.errors.txt @@ -0,0 +1 @@ +3:23:Cannot assign to property of unknown type "SomethingUnknown*". diff --git a/tests/auto/qml/qqmllanguage/data/propertyUnknownType.qml b/tests/auto/qml/qqmllanguage/data/propertyUnknownType.qml new file mode 100644 index 0000000000..c22fd65350 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/propertyUnknownType.qml @@ -0,0 +1,4 @@ +import Test 1.0 +MyQmlObject { + somethingUnknown: SomethingKnown {} +} diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp index ffb1d51971..6956533196 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.cpp +++ b/tests/auto/qml/qqmllanguage/testtypes.cpp @@ -62,6 +62,7 @@ void registerTypes() qmlRegisterType("Test",1,1,"MyRevisionedClass"); qmlRegisterType("Test",1,0,"MyRevisionedIllegalOverload"); qmlRegisterType("Test",1,0,"MyRevisionedLegalOverload"); + qmlRegisterType("Test",1,0,"SomethingKnown"); // Register the uncreatable base class qmlRegisterRevision("Test",1,1); diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h index 0618d2b20f..1aab24841a 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.h +++ b/tests/auto/qml/qqmllanguage/testtypes.h @@ -89,6 +89,14 @@ private: int m_value2; }; +class SomethingUnknown : public QObject { + Q_OBJECT +}; + +class SomethingKnown : public SomethingUnknown { + Q_OBJECT +}; + class MyQmlObject : public QObject, public MyInterface { Q_OBJECT @@ -104,6 +112,7 @@ class MyQmlObject : public QObject, public MyInterface Q_PROPERTY(int propertyWithNotify READ propertyWithNotify WRITE setPropertyWithNotify NOTIFY oddlyNamedNotifySignal) Q_PROPERTY(int nonScriptable READ nonScriptable WRITE setNonScriptable SCRIPTABLE false) Q_PROPERTY(QJSValue qjsvalue READ qjsvalue WRITE setQJSValue NOTIFY qjsvalueChanged) + Q_PROPERTY(SomethingUnknown* somethingUnknown READ somethingUnknown WRITE setSomethingUnknown NOTIFY somethingUnknownChanged) Q_INTERFACES(MyInterface) public: @@ -151,6 +160,9 @@ public: int childAddedEventCount() const { return m_childAddedEventCount; } + SomethingUnknown* somethingUnknown() const { return nullptr; } + void setSomethingUnknown(SomethingUnknown* something) { Q_UNUSED(something); } + public slots: void basicSlot() { qWarning("MyQmlObject::basicSlot"); } void basicSlotWithArgs(int v) { qWarning("MyQmlObject::basicSlotWithArgs(%d)", v); } @@ -162,6 +174,7 @@ signals: void oddlyNamedNotifySignal(); void signalWithDefaultArg(int parameter = 5); void qjsvalueChanged(); + void somethingUnknownChanged(); protected: virtual bool event(QEvent *event); diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 27b550457d..8adacd8829 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -626,8 +626,9 @@ void tst_qqmllanguage::errors_data() QTest::newRow("bareQmlImport") << "bareQmlImport.qml" << "bareQmlImport.errors.txt" << false; QTest::newRow("typeAnnotations.2") << "typeAnnotations.2.qml" << "typeAnnotations.2.errors.txt" << false; -} + QTest::newRow("propertyUnknownType") << "propertyUnknownType.qml" << "propertyUnknownType.errors.txt" << false; +} void tst_qqmllanguage::errors() { -- cgit v1.2.3 From f6393ed0e4608bad4653f524c188bdc928e2d3b7 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Thu, 4 Jul 2019 10:27:19 +0200 Subject: QQuickImageBase: prepare for rescalable PDF as an image format QQuickImageBasePrivate::updateDevicePixelRatio() assumes that only SVG or an image provider can provide a scalable image. Now that PDF will be supported, we can add it to the list. Change-Id: I9a6df7c58cb9db0e8d4d159c138bedd481281d92 Reviewed-by: Eirik Aavitsland --- src/quick/items/qquickimagebase.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/quick/items/qquickimagebase.cpp b/src/quick/items/qquickimagebase.cpp index 729d326625..40857964a9 100644 --- a/src/quick/items/qquickimagebase.cpp +++ b/src/quick/items/qquickimagebase.cpp @@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE // if they're not happy with our implementation of it. bool QQuickImageBasePrivate::updateDevicePixelRatio(qreal targetDevicePixelRatio) { - // QQuickImageProvider and SVG can generate a high resolution image when + // QQuickImageProvider and SVG and PDF can generate a high resolution image when // sourceSize is set (this function is only called if it's set). // If sourceSize is not set then the provider default size will be used, as usual. bool setDevicePixelRatio = false; @@ -64,7 +64,8 @@ bool QQuickImageBasePrivate::updateDevicePixelRatio(qreal targetDevicePixelRatio } else { QString stringUrl = url.path(QUrl::PrettyDecoded); if (stringUrl.endsWith(QLatin1String("svg")) || - stringUrl.endsWith(QLatin1String("svgz"))) { + stringUrl.endsWith(QLatin1String("svgz")) || + stringUrl.endsWith(QLatin1String("pdf"))) { setDevicePixelRatio = true; } } -- cgit v1.2.3 From 506b4093b47f8ecf29c2e1e83e73e47e9ac767ad Mon Sep 17 00:00:00 2001 From: Sona Kurazyan Date: Fri, 2 Aug 2019 14:41:10 +0200 Subject: Remove usages of deprecated APIs of QWheelEvent Task-number: QTBUG-76491 Change-Id: I69b0c4ec7c03f9421b18828516e064eff2b45518 Reviewed-by: Shawn Rutledge --- src/qmltest/quicktestevent.cpp | 3 ++- src/quick/items/qquickevents.cpp | 2 +- src/quick/items/qquickflickable.cpp | 5 +++-- src/quick/items/qquickmousearea.cpp | 2 +- tests/auto/quick/qquickflickable/tst_qquickflickable.cpp | 15 ++++++++++----- tests/auto/quick/qquickitem/tst_qquickitem.cpp | 7 ++++--- tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp | 2 +- 7 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/qmltest/quicktestevent.cpp b/src/qmltest/quicktestevent.cpp index 5b07220c29..1e949615c2 100644 --- a/src/qmltest/quicktestevent.cpp +++ b/src/qmltest/quicktestevent.cpp @@ -241,7 +241,8 @@ namespace QtQuickTest QTEST_ASSERT(stateKey == 0 || stateKey & Qt::KeyboardModifierMask); stateKey &= static_cast(Qt::KeyboardModifierMask); - QWheelEvent we(pos, window->mapToGlobal(pos), QPoint(0, 0), QPoint(xDelta, yDelta), 0, Qt::Vertical, buttons, stateKey); + QWheelEvent we(pos, window->mapToGlobal(pos), QPoint(0, 0), QPoint(xDelta, yDelta), buttons, + stateKey, Qt::NoScrollPhase, false); QSpontaneKeyEvent::setSpontaneous(&we); // hmmmm if (!qApp->notify(window, &we)) diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp index 8303c3fed1..161ef17e1f 100644 --- a/src/quick/items/qquickevents.cpp +++ b/src/quick/items/qquickevents.cpp @@ -1448,7 +1448,7 @@ QQuickPointerEvent *QQuickPointerScrollEvent::reset(QEvent *event) m_synthSource = ev->source(); m_inverted = ev->inverted(); - m_point->reset(Qt::TouchPointMoved, ev->posF(), quint64(1) << 24, ev->timestamp()); // mouse has device ID 1 + m_point->reset(Qt::TouchPointMoved, ev->position(), quint64(1) << 24, ev->timestamp()); // mouse has device ID 1 } #endif // TODO else if (event->type() == QEvent::Scroll) ... diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index 7e1f54f07e..cf3cd9f48e 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -1489,7 +1489,7 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event) d->vData.velocity = 0; d->hData.velocity = 0; d->timer.start(); - d->maybeBeginDrag(currentTimestamp, event->posF()); + d->maybeBeginDrag(currentTimestamp, event->position()); break; case Qt::NoScrollPhase: // default phase with an ordinary wheel mouse case Qt::ScrollUpdate: @@ -1571,7 +1571,8 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event) QVector2D velocity(xDelta / elapsed, yDelta / elapsed); d->lastPosTime = currentTimestamp; d->accumulatedWheelPixelDelta += QVector2D(event->pixelDelta()); - d->drag(currentTimestamp, event->type(), event->posF(), d->accumulatedWheelPixelDelta, true, !d->scrollingPhase, true, velocity); + d->drag(currentTimestamp, event->type(), event->position(), d->accumulatedWheelPixelDelta, + true, !d->scrollingPhase, true, velocity); event->accept(); } diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp index bce7ec718b..a8f09dc8be 100644 --- a/src/quick/items/qquickmousearea.cpp +++ b/src/quick/items/qquickmousearea.cpp @@ -899,7 +899,7 @@ void QQuickMouseArea::wheelEvent(QWheelEvent *event) } QQuickWheelEvent &we = d->quickWheelEvent; - we.reset(event->posF().x(), event->posF().y(), event->angleDelta(), event->pixelDelta(), + we.reset(event->position().x(), event->position().y(), event->angleDelta(), event->pixelDelta(), event->buttons(), event->modifiers(), event->inverted()); we.setAccepted(d->isWheelConnected()); emit wheel(&we); diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index 2314b82e8c..c104eecbcd 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -874,7 +874,8 @@ void tst_qquickflickable::wheel() // test a vertical flick { QPoint pos(200, 200); - QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(), QPoint(0,-120), -120, Qt::Vertical, Qt::NoButton, Qt::NoModifier); + QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(), QPoint(0,-120), + Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); event.setAccepted(false); QGuiApplication::sendEvent(window.data(), &event); } @@ -897,7 +898,8 @@ void tst_qquickflickable::wheel() // test a horizontal flick { QPoint pos(200, 200); - QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(), QPoint(-120,0), -120, Qt::Horizontal, Qt::NoButton, Qt::NoModifier); + QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(), QPoint(-120,0), + Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); event.setAccepted(false); QGuiApplication::sendEvent(window.data(), &event); @@ -926,7 +928,8 @@ void tst_qquickflickable::trackpad() QPoint pos(200, 200); { - QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(0,-100), QPoint(0,-120), -120, Qt::Vertical, Qt::NoButton, Qt::NoModifier, Qt::ScrollBegin); + QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(0,-100), QPoint(0,-120), + Qt::NoButton, Qt::NoModifier, Qt::ScrollBegin, false); event.setAccepted(false); QGuiApplication::sendEvent(window.data(), &event); } @@ -938,7 +941,8 @@ void tst_qquickflickable::trackpad() QCOMPARE(flick->contentY(), qreal(0)); { - QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(-100,0), QPoint(-120,0), -120, Qt::Horizontal, Qt::NoButton, Qt::NoModifier, Qt::ScrollUpdate); + QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(-100,0), QPoint(-120,0), + Qt::NoButton, Qt::NoModifier, Qt::ScrollUpdate, false); event.setAccepted(false); QGuiApplication::sendEvent(window.data(), &event); } @@ -947,7 +951,8 @@ void tst_qquickflickable::trackpad() QCOMPARE(flick->contentY(), qreal(0)); { - QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(0,0), QPoint(0,0), 0, Qt::Horizontal, Qt::NoButton, Qt::NoModifier, Qt::ScrollEnd); + QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(0,0), QPoint(0,0), + Qt::NoButton, Qt::NoModifier, Qt::ScrollEnd, false); event.setAccepted(false); QGuiApplication::sendEvent(window.data(), &event); } diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp index 7e132f97b6..b6e40d5117 100644 --- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp +++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp @@ -83,8 +83,8 @@ protected: event->accept(); ++wheelCount; timestamp = event->timestamp(); - lastWheelEventPos = event->pos(); - lastWheelEventGlobalPos = event->globalPos(); + lastWheelEventPos = event->position().toPoint(); + lastWheelEventGlobalPos = event->globalPosition().toPoint(); } }; @@ -1462,7 +1462,8 @@ void tst_qquickitem::wheelEvent() QPoint localPoint(width / 2, height / 2); QPoint globalPoint = window.mapToGlobal(localPoint); - QWheelEvent event(localPoint, globalPoint, -120, Qt::NoButton, Qt::NoModifier, Qt::Vertical); + QWheelEvent event(localPoint, globalPoint, QPoint(0, 0), QPoint(0, -120), + Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); event.setTimestamp(123456UL); event.setAccepted(false); QGuiApplication::sendEvent(&window, &event); diff --git a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp index 4215017db3..5844720aa4 100644 --- a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp +++ b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp @@ -1519,7 +1519,7 @@ void tst_QQuickMouseArea::onWheel() QVERIFY(root != nullptr); QWheelEvent wheelEvent(QPoint(10, 32), QPoint(10, 32), QPoint(60, 20), QPoint(0, 120), - 0, Qt::Vertical,Qt::NoButton, Qt::ControlModifier); + Qt::NoButton, Qt::ControlModifier, Qt::NoScrollPhase, false); QGuiApplication::sendEvent(&window, &wheelEvent); QCOMPARE(root->property("angleDeltaY").toInt(), 120); -- cgit v1.2.3 From 5d995ae122aa07486ead849560b74d2b62b883bb Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Thu, 3 Dec 2015 17:48:38 +0100 Subject: Move currentFrame and frameCount properties up to QQuickImageBase AnimatedImage already had these properties, but some typically non-animated image formats such as PDF, TIFF and ICO can also support multiple pages. In either case, the currentFrame property can be used to select a specific frame or page. However an AnimatedImage uses a QMovie to do that, whereas a plain Image uses QQuickPixmap. So the accessors need to be virtual in order to have these different implementations. [ChangeLog][QtQuick][Image] Image and BorderImage now have currentFrame and frameCount properties which can be used to step through the frames of multi-page image formats such as TIFF, WEBP and ICO. Task-number: QTBUG-77506 Change-Id: Id4d95a99a26a862957e44b1bd8ffe06d7eababef Reviewed-by: Eirik Aavitsland --- examples/quick/imageelements/content/multi.ico | Bin 0 -> 27110 bytes examples/quick/imageelements/framestepping.qml | 82 ++++++++++++++++++++ examples/quick/imageelements/imageelements.qml | 2 + examples/quick/imageelements/imageelements.qrc | 3 + .../quick/imageelements/multiframeborderimage.qml | 83 +++++++++++++++++++++ src/quick/items/qquickanimatedimage.cpp | 6 +- src/quick/items/qquickanimatedimage_p.h | 6 +- src/quick/items/qquickborderimage.cpp | 18 ++++- src/quick/items/qquickimage.cpp | 12 +++ src/quick/items/qquickimagebase.cpp | 37 ++++++++- src/quick/items/qquickimagebase_p.h | 9 +++ src/quick/items/qquickimagebase_p_p.h | 6 +- src/quick/items/qquickitemsmodule.cpp | 3 + src/quick/util/qquickpixmapcache.cpp | 81 +++++++++++++------- src/quick/util/qquickpixmapcache_p.h | 5 +- tests/auto/quick/qquickborderimage/data/multi.ico | Bin 0 -> 27110 bytes .../quick/qquickborderimage/data/multiframe.qml | 8 ++ .../qquickborderimage/data/multiframeAsync.qml | 9 +++ .../qquickborderimage/tst_qquickborderimage.cpp | 53 +++++++++++++ tests/auto/quick/qquickimage/data/multi.ico | Bin 0 -> 27110 bytes tests/auto/quick/qquickimage/data/multiframe.qml | 5 ++ .../quick/qquickimage/data/multiframeAsync.qml | 6 ++ tests/auto/quick/qquickimage/tst_qquickimage.cpp | 52 +++++++++++++ 23 files changed, 447 insertions(+), 39 deletions(-) create mode 100644 examples/quick/imageelements/content/multi.ico create mode 100644 examples/quick/imageelements/framestepping.qml create mode 100644 examples/quick/imageelements/multiframeborderimage.qml create mode 100644 tests/auto/quick/qquickborderimage/data/multi.ico create mode 100644 tests/auto/quick/qquickborderimage/data/multiframe.qml create mode 100644 tests/auto/quick/qquickborderimage/data/multiframeAsync.qml create mode 100644 tests/auto/quick/qquickimage/data/multi.ico create mode 100644 tests/auto/quick/qquickimage/data/multiframe.qml create mode 100644 tests/auto/quick/qquickimage/data/multiframeAsync.qml diff --git a/examples/quick/imageelements/content/multi.ico b/examples/quick/imageelements/content/multi.ico new file mode 100644 index 0000000000..b748ceaa29 Binary files /dev/null and b/examples/quick/imageelements/content/multi.ico differ diff --git a/examples/quick/imageelements/framestepping.qml b/examples/quick/imageelements/framestepping.qml new file mode 100644 index 0000000000..f5bad46e7b --- /dev/null +++ b/examples/quick/imageelements/framestepping.qml @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, 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$ +** +****************************************************************************/ + +import QtQuick 2.14 + +Rectangle { + width: 480 + height: 320 + Image { + id: img + anchors.centerIn: parent + cache: true + source: "content/multi.ico" + + Shortcut { + sequence: StandardKey.MoveToNextPage + enabled: img.currentFrame < img.frameCount - 1 + onActivated: img.currentFrame++ + } + Shortcut { + sequence: StandardKey.MoveToPreviousPage + enabled: img.currentFrame > 0 + onActivated: img.currentFrame-- + } + } + + Text { + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + anchors.margins: 6 + horizontalAlignment: Text.AlignHCenter + text: "frame " + (img.currentFrame + 1) + " of " + img.frameCount + + "\nPress PgUp/PgDn to switch frames" + } +} diff --git a/examples/quick/imageelements/imageelements.qml b/examples/quick/imageelements/imageelements.qml index dfb4d24ea6..91f2e034f7 100644 --- a/examples/quick/imageelements/imageelements.qml +++ b/examples/quick/imageelements/imageelements.qml @@ -64,6 +64,8 @@ Item { addExample("AnimatedImage", "An image which plays animated formats", Qt.resolvedUrl("animatedimage.qml")); addExample("AnimatedSprite", "A simple sprite-based animation", Qt.resolvedUrl("animatedsprite.qml")); addExample("SpriteSequence", "A sprite-based animation with complex transitions", Qt.resolvedUrl("spritesequence.qml")); + addExample("FrameStepping", "A multi-frame non-animated image", Qt.resolvedUrl("framestepping.qml")); + addExample("MultiBorderImage", "A multi-frame image with scaled borders", Qt.resolvedUrl("multiframeborderimage.qml")); } } } diff --git a/examples/quick/imageelements/imageelements.qrc b/examples/quick/imageelements/imageelements.qrc index 2488fb083b..cedef2204c 100644 --- a/examples/quick/imageelements/imageelements.qrc +++ b/examples/quick/imageelements/imageelements.qrc @@ -8,6 +8,7 @@ content/colors-stretch.sci content/colors.png content/ImageCell.qml + content/multi.ico content/MyBorderImage.qml content/qt-logo.png content/shadow.png @@ -18,6 +19,8 @@ animatedimage.qml animatedsprite.qml borderimage.qml + framestepping.qml + multiframeborderimage.qml image.qml shadows.qml spritesequence.qml diff --git a/examples/quick/imageelements/multiframeborderimage.qml b/examples/quick/imageelements/multiframeborderimage.qml new file mode 100644 index 0000000000..0805ea4243 --- /dev/null +++ b/examples/quick/imageelements/multiframeborderimage.qml @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, 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$ +** +****************************************************************************/ + +import QtQuick 2.14 + +Rectangle { + width: 480 + height: 320 + BorderImage { + id: img + anchors.fill: parent + anchors.margins: 6 + cache: true + source: "content/multi.ico" + border { left: 19; top: 19; right: 19; bottom: 19 } + horizontalTileMode: BorderImage.Stretch + + Shortcut { + sequence: StandardKey.MoveToNextPage + enabled: img.currentFrame < img.frameCount - 1 + onActivated: img.currentFrame++ + } + Shortcut { + sequence: StandardKey.MoveToPreviousPage + enabled: img.currentFrame > 0 + onActivated: img.currentFrame-- + } + } + + Text { + anchors.centerIn: parent + horizontalAlignment: Text.AlignHCenter + text: "frame " + (img.currentFrame + 1) + " of " + img.frameCount + + "\nPress PgUp/PgDn to switch frames" + } +} diff --git a/src/quick/items/qquickanimatedimage.cpp b/src/quick/items/qquickanimatedimage.cpp index fe445425e7..bebefc1b22 100644 --- a/src/quick/items/qquickanimatedimage.cpp +++ b/src/quick/items/qquickanimatedimage.cpp @@ -67,7 +67,7 @@ QQuickPixmap* QQuickAnimatedImagePrivate::infoForCurrentFrame(QQmlEngine *engine .arg(current)); } if (!requestedUrl.isEmpty()) { - if (QQuickPixmap::isCached(requestedUrl, QSize(), QQuickImageProviderOptions())) + if (QQuickPixmap::isCached(requestedUrl, QSize(), 0, QQuickImageProviderOptions())) pixmap = new QQuickPixmap(engine, requestedUrl); else pixmap = new QQuickPixmap(requestedUrl, movie->currentImage()); @@ -139,6 +139,8 @@ QQuickAnimatedImage::QQuickAnimatedImage(QQuickItem *parent) : QQuickImage(*(new QQuickAnimatedImagePrivate), parent) { connect(this, &QQuickImageBase::cacheChanged, this, &QQuickAnimatedImage::onCacheChanged); + connect(this, &QQuickImageBase::currentFrameChanged, this, &QQuickAnimatedImage::frameChanged); + connect(this, &QQuickImageBase::frameCountChanged, this, &QQuickAnimatedImage::frameCountChanged); } QQuickAnimatedImage::~QQuickAnimatedImage() @@ -464,7 +466,7 @@ void QQuickAnimatedImage::movieUpdate() if (d->movie) { d->setPixmap(*d->infoForCurrentFrame(qmlEngine(this))); - emit frameChanged(); + emit currentFrameChanged(); } } diff --git a/src/quick/items/qquickanimatedimage_p.h b/src/quick/items/qquickanimatedimage_p.h index 6b5db215bd..ef5af6b387 100644 --- a/src/quick/items/qquickanimatedimage_p.h +++ b/src/quick/items/qquickanimatedimage_p.h @@ -85,10 +85,10 @@ public: bool isPaused() const; void setPaused(bool pause); - int currentFrame() const; - void setCurrentFrame(int frame); + int currentFrame() const override; + void setCurrentFrame(int frame) override; - int frameCount() const; + int frameCount() const override; qreal speed() const; void setSpeed(qreal speed); diff --git a/src/quick/items/qquickborderimage.cpp b/src/quick/items/qquickborderimage.cpp index c53a39ca09..430fa1b094 100644 --- a/src/quick/items/qquickborderimage.cpp +++ b/src/quick/items/qquickborderimage.cpp @@ -343,7 +343,7 @@ void QQuickBorderImage::load() QUrl loadUrl = d->url; resolve2xLocalFile(d->url, targetDevicePixelRatio, &loadUrl, &d->devicePixelRatio); - d->pix.load(qmlEngine(this), loadUrl, d->sourcesize * d->devicePixelRatio, options); + d->pix.load(qmlEngine(this), loadUrl, d->sourcesize * d->devicePixelRatio, options, QQuickImageProviderOptions(), d->currentFrame, d->frameCount); if (d->pix.isLoading()) { if (d->progress != 0.0) { @@ -534,6 +534,10 @@ void QQuickBorderImage::requestFinished() d->oldSourceSize = sourceSize(); emit sourceSizeChanged(); } + if (d->frameCount != d->pix.frameCount()) { + d->frameCount = d->pix.frameCount(); + emit frameCountChanged(); + } pixmapChange(); } @@ -693,6 +697,18 @@ void QQuickBorderImage::pixmapChange() update(); } +/*! + \qmlproperty int QtQuick::BorderImage::currentFrame + \qmlproperty int QtQuick::BorderImage::frameCount + \since 5.14 + + currentFrame is the frame that is currently visible. The default is \c 0. + You can set it to a number between \c 0 and \c {frameCount - 1} to display a + different frame, if the image contains multiple frames. + + frameCount is the number of frames in the image. Most images have only one frame. +*/ + QT_END_NAMESPACE #include "moc_qquickborderimage_p.cpp" diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp index dfbe271606..87b848b21b 100644 --- a/src/quick/items/qquickimage.cpp +++ b/src/quick/items/qquickimage.cpp @@ -889,4 +889,16 @@ void QQuickImage::setMipmap(bool use) By default, this property is set to false. */ +/*! + \qmlproperty int QtQuick::Image::currentFrame + \qmlproperty int QtQuick::Image::frameCount + \since 5.14 + + currentFrame is the frame that is currently visible. The default is \c 0. + You can set it to a number between \c 0 and \c {frameCount - 1} to display a + different frame, if the image contains multiple frames. + + frameCount is the number of frames in the image. Most images have only one frame. +*/ + QT_END_NAMESPACE diff --git a/src/quick/items/qquickimagebase.cpp b/src/quick/items/qquickimagebase.cpp index 40857964a9..8bab14bfd1 100644 --- a/src/quick/items/qquickimagebase.cpp +++ b/src/quick/items/qquickimagebase.cpp @@ -211,6 +211,36 @@ bool QQuickImageBase::mirror() const return d->mirror; } +void QQuickImageBase::setCurrentFrame(int frame) +{ + Q_D(QQuickImageBase); + if (frame == d->currentFrame || frame < 0 || (isComponentComplete() && frame >= d->pix.frameCount())) + return; + + d->currentFrame = frame; + + if (isComponentComplete()) { + if (frame > 0) + d->cache = false; + load(); + update(); + } + + emit currentFrameChanged(); +} + +int QQuickImageBase::currentFrame() const +{ + Q_D(const QQuickImageBase); + return d->currentFrame; +} + +int QQuickImageBase::frameCount() const +{ + Q_D(const QQuickImageBase); + return d->frameCount; +} + void QQuickImageBase::load() { Q_D(QQuickImageBase); @@ -261,7 +291,7 @@ void QQuickImageBase::load() resolve2xLocalFile(d->url, targetDevicePixelRatio, &loadUrl, &d->devicePixelRatio); } - d->pix.load(qmlEngine(this), loadUrl, d->sourcesize * d->devicePixelRatio, options, d->providerOptions); + d->pix.load(qmlEngine(this), loadUrl, d->sourcesize * d->devicePixelRatio, options, d->providerOptions, d->currentFrame, d->frameCount); if (d->pix.isLoading()) { if (d->progress != 0.0) { @@ -320,6 +350,11 @@ void QQuickImageBase::requestFinished() d->oldAutoTransform = autoTransform(); emitAutoTransformBaseChanged(); } + if (d->frameCount != d->pix.frameCount()) { + d->frameCount = d->pix.frameCount(); + emit frameCountChanged(); + } + update(); } diff --git a/src/quick/items/qquickimagebase_p.h b/src/quick/items/qquickimagebase_p.h index d8d0be9b8c..8cd59c8cea 100644 --- a/src/quick/items/qquickimagebase_p.h +++ b/src/quick/items/qquickimagebase_p.h @@ -68,6 +68,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickImageBase : public QQuickImplicitSizeItem Q_PROPERTY(bool cache READ cache WRITE setCache NOTIFY cacheChanged) Q_PROPERTY(QSize sourceSize READ sourceSize WRITE setSourceSize RESET resetSourceSize NOTIFY sourceSizeChanged) Q_PROPERTY(bool mirror READ mirror WRITE setMirror NOTIFY mirrorChanged) + Q_PROPERTY(int currentFrame READ currentFrame WRITE setCurrentFrame NOTIFY currentFrameChanged REVISION 14) + Q_PROPERTY(int frameCount READ frameCount NOTIFY frameCountChanged REVISION 14) public: QQuickImageBase(QQuickItem *parent=nullptr); @@ -95,6 +97,11 @@ public: virtual void setMirror(bool mirror); bool mirror() const; + virtual void setCurrentFrame(int frame); + virtual int currentFrame() const; + + virtual int frameCount() const; + virtual void setAutoTransform(bool transform); bool autoTransform() const; @@ -112,6 +119,8 @@ Q_SIGNALS: void asynchronousChanged(); void cacheChanged(); void mirrorChanged(); + Q_REVISION(14) void currentFrameChanged(); + Q_REVISION(14) void frameCountChanged(); protected: virtual void load(); diff --git a/src/quick/items/qquickimagebase_p_p.h b/src/quick/items/qquickimagebase_p_p.h index 1b771166a2..88e18ba32e 100644 --- a/src/quick/items/qquickimagebase_p_p.h +++ b/src/quick/items/qquickimagebase_p_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQuick module of the Qt Toolkit. @@ -68,6 +68,8 @@ public: : status(QQuickImageBase::Null), progress(0.0), devicePixelRatio(1.0), + currentFrame(0), + frameCount(0), async(false), cache(true), mirror(false), @@ -85,6 +87,8 @@ public: QSize oldSourceSize; qreal devicePixelRatio; QQuickImageProviderOptions providerOptions; + int currentFrame; + int frameCount; bool async : 1; bool cache : 1; bool mirror: 1; diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index d8ad104a6d..6ce079a0dc 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -491,6 +491,9 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) #if QT_CONFIG(wheelevent) qmlRegisterType(uri, 2, 14, "WheelHandler"); #endif + qmlRegisterUncreatableType(uri, 2, 14, "ImageBase", + QQuickPointerHandler::tr("ImageBase is an abstract base class")); + qmlRegisterType(uri, 2, 14, "Image"); } static void initResources() diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp index 78a4e5b998..56ad8ebf0b 100644 --- a/src/quick/util/qquickpixmapcache.cpp +++ b/src/quick/util/qquickpixmapcache.cpp @@ -241,7 +241,7 @@ class QQuickPixmapData { public: QQuickPixmapData(QQuickPixmap *pixmap, const QUrl &u, const QSize &s, const QQuickImageProviderOptions &po, const QString &e) - : refCount(1), inCache(false), pixmapStatus(QQuickPixmap::Error), + : refCount(1), frameCount(1), frame(0), inCache(false), pixmapStatus(QQuickPixmap::Error), url(u), errorString(e), requestSize(s), providerOptions(po), appliedTransform(QQuickImageProviderOptions::UsePluginDefaultTransform), textureFactory(nullptr), reply(nullptr), prevUnreferenced(nullptr), @@ -250,8 +250,8 @@ public: declarativePixmaps.insert(pixmap); } - QQuickPixmapData(QQuickPixmap *pixmap, const QUrl &u, const QSize &r, const QQuickImageProviderOptions &po, QQuickImageProviderOptions::AutoTransform aTransform) - : refCount(1), inCache(false), pixmapStatus(QQuickPixmap::Loading), + QQuickPixmapData(QQuickPixmap *pixmap, const QUrl &u, const QSize &r, const QQuickImageProviderOptions &po, QQuickImageProviderOptions::AutoTransform aTransform, int frame=0, int frameCount=1) + : refCount(1), frameCount(frameCount), frame(frame), inCache(false), pixmapStatus(QQuickPixmap::Loading), url(u), requestSize(r), providerOptions(po), appliedTransform(aTransform), textureFactory(nullptr), reply(nullptr), prevUnreferenced(nullptr), prevUnreferencedPtr(nullptr), @@ -261,8 +261,8 @@ public: } QQuickPixmapData(QQuickPixmap *pixmap, const QUrl &u, QQuickTextureFactory *texture, - const QSize &s, const QSize &r, const QQuickImageProviderOptions &po, QQuickImageProviderOptions::AutoTransform aTransform) - : refCount(1), inCache(false), pixmapStatus(QQuickPixmap::Ready), + const QSize &s, const QSize &r, const QQuickImageProviderOptions &po, QQuickImageProviderOptions::AutoTransform aTransform, int frame=0, int frameCount=1) + : refCount(1), frameCount(frameCount), frame(frame), inCache(false), pixmapStatus(QQuickPixmap::Ready), url(u), implicitSize(s), requestSize(r), providerOptions(po), appliedTransform(aTransform), textureFactory(texture), reply(nullptr), prevUnreferenced(nullptr), @@ -272,7 +272,7 @@ public: } QQuickPixmapData(QQuickPixmap *pixmap, QQuickTextureFactory *texture) - : refCount(1), inCache(false), pixmapStatus(QQuickPixmap::Ready), + : refCount(1), frameCount(1), frame(0), inCache(false), pixmapStatus(QQuickPixmap::Ready), appliedTransform(QQuickImageProviderOptions::UsePluginDefaultTransform), textureFactory(texture), reply(nullptr), prevUnreferenced(nullptr), prevUnreferencedPtr(nullptr), nextUnreferenced(nullptr) @@ -299,6 +299,8 @@ public: void removeFromCache(); uint refCount; + int frameCount; + int frame; bool inCache:1; @@ -396,9 +398,9 @@ static void maybeRemoveAlpha(QImage *image) } } -static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *errorString, QSize *impsize, +static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *errorString, QSize *impsize, int *frameCount, const QSize &requestSize, const QQuickImageProviderOptions &providerOptions, - QQuickImageProviderOptions::AutoTransform *appliedTransform = nullptr) + QQuickImageProviderOptions::AutoTransform *appliedTransform = nullptr, int frame = 0) { QImageReader imgio(dev); if (providerOptions.autoTransform() != QQuickImageProviderOptions::UsePluginDefaultTransform) @@ -406,6 +408,12 @@ static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *e else if (appliedTransform) *appliedTransform = imgio.autoTransform() ? QQuickImageProviderOptions::ApplyTransform : QQuickImageProviderOptions::DoNotApplyTransform; + if (frame < imgio.imageCount()) + imgio.jumpToImage(frame); + + if (frameCount) + *frameCount = imgio.imageCount(); + QSize scSize = QQuickImageProviderWithOptions::loadSize(imgio.size(), requestSize, imgio.format(), providerOptions); if (scSize.isValid()) imgio.setScaledSize(scSize); @@ -558,9 +566,12 @@ void QQuickPixmapReader::networkRequestDone(QNetworkReply *reply) QByteArray all = reply->readAll(); QBuffer buff(&all); buff.open(QIODevice::ReadOnly); - if (!readImage(reply->url(), &buff, &image, &errorString, &readSize, job->requestSize, job->providerOptions)) + int frameCount; + if (!readImage(reply->url(), &buff, &image, &errorString, &readSize, &frameCount, job->requestSize, job->providerOptions, nullptr, job->data->frame)) error = QQuickPixmapReply::Decoding; - } + else + job->data->frameCount = frameCount; + } // send completion event to the QQuickPixmapReply mutex.lock(); if (!cancelled.contains(job)) @@ -870,10 +881,13 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u mutex.unlock(); return; } else { - if (!readImage(url, &f, &image, &errorStr, &readSize, runningJob->requestSize, runningJob->providerOptions)) { + int frameCount; + if (!readImage(url, &f, &image, &errorStr, &readSize, &frameCount, runningJob->requestSize, runningJob->providerOptions, nullptr, runningJob->data->frame)) { errorCode = QQuickPixmapReply::Loading; if (f.fileName() != localFile) errorStr += QString::fromLatin1(" (%1)").arg(f.fileName()); + } else if (runningJob->data) { + runningJob->data->frameCount = frameCount; } } } else { @@ -982,17 +996,18 @@ class QQuickPixmapKey public: const QUrl *url; const QSize *size; + int frame; QQuickImageProviderOptions options; }; inline bool operator==(const QQuickPixmapKey &lhs, const QQuickPixmapKey &rhs) { - return *lhs.size == *rhs.size && *lhs.url == *rhs.url && lhs.options == rhs.options; + return *lhs.size == *rhs.size && *lhs.url == *rhs.url && lhs.options == rhs.options && lhs.frame == rhs.frame; } inline uint qHash(const QQuickPixmapKey &key) { - return qHash(*key.url) ^ (key.size->width()*7) ^ (key.size->height()*17) ^ (key.options.autoTransform() * 0x5c5c5c5c); + return qHash(*key.url) ^ (key.size->width()*7) ^ (key.size->height()*17) ^ (key.frame*23) ^ (key.options.autoTransform() * 0x5c5c5c5c); } class QQuickPixmapStore : public QObject @@ -1254,7 +1269,7 @@ void QQuickPixmapData::release() void QQuickPixmapData::addToCache() { if (!inCache) { - QQuickPixmapKey key = { &url, &requestSize, providerOptions }; + QQuickPixmapKey key = { &url, &requestSize, frame, providerOptions }; pixmapStore()->m_cache.insert(key, this); inCache = true; PIXMAP_PROFILE(pixmapCountChanged( @@ -1265,7 +1280,7 @@ void QQuickPixmapData::addToCache() void QQuickPixmapData::removeFromCache() { if (inCache) { - QQuickPixmapKey key = { &url, &requestSize, providerOptions }; + QQuickPixmapKey key = { &url, &requestSize, frame, providerOptions }; pixmapStore()->m_cache.remove(key); inCache = false; PIXMAP_PROFILE(pixmapCountChanged( @@ -1273,7 +1288,7 @@ void QQuickPixmapData::removeFromCache() } } -static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, QQmlEngine *engine, const QUrl &url, const QSize &requestSize, const QQuickImageProviderOptions &providerOptions, bool *ok) +static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, QQmlEngine *engine, const QUrl &url, const QSize &requestSize, const QQuickImageProviderOptions &providerOptions, int frame, bool *ok) { if (url.scheme() == QLatin1String("image")) { QSize readSize; @@ -1296,7 +1311,7 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q : provider->requestTexture(imageId(url), &readSize, requestSize); if (texture) { *ok = true; - return new QQuickPixmapData(declarativePixmap, url, texture, readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform); + return new QQuickPixmapData(declarativePixmap, url, texture, readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform, frame); } break; } @@ -1307,7 +1322,7 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q : provider->requestImage(imageId(url), &readSize, requestSize); if (!image.isNull()) { *ok = true; - return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform); + return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform, frame); } break; } @@ -1317,7 +1332,7 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q : provider->requestPixmap(imageId(url), &readSize, requestSize); if (!pixmap.isNull()) { *ok = true; - return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(pixmap.toImage()), readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform); + return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(pixmap.toImage()), readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform, frame); } break; } @@ -1347,7 +1362,7 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q QQuickTextureFactory *factory = texReader.read(); if (factory) { *ok = true; - return new QQuickPixmapData(declarativePixmap, url, factory, factory->textureSize(), requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform); + return new QQuickPixmapData(declarativePixmap, url, factory, factory->textureSize(), requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform, frame); } else { errorString = QQuickPixmap::tr("Error decoding: %1").arg(url.toString()); if (f.fileName() != localFile) @@ -1356,9 +1371,10 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q } else { QImage image; QQuickImageProviderOptions::AutoTransform appliedTransform = providerOptions.autoTransform(); - if (readImage(url, &f, &image, &errorString, &readSize, requestSize, providerOptions, &appliedTransform)) { + int frameCount; + if (readImage(url, &f, &image, &errorString, &readSize, &frameCount, requestSize, providerOptions, &appliedTransform, frame)) { *ok = true; - return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, providerOptions, appliedTransform); + return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, providerOptions, appliedTransform, frame, frameCount); } else if (f.fileName() != localFile) { errorString += QString::fromLatin1(" (%1)").arg(f.fileName()); } @@ -1476,6 +1492,13 @@ QQuickImageProviderOptions::AutoTransform QQuickPixmap::autoTransform() const return QQuickImageProviderOptions::UsePluginDefaultTransform; } +int QQuickPixmap::frameCount() const +{ + if (d) + return d->frameCount; + return 0; +} + QQuickTextureFactory *QQuickPixmap::textureFactory() const { if (d) @@ -1554,7 +1577,7 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques load(engine, url, requestSize, options, QQuickImageProviderOptions()); } -void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &requestSize, QQuickPixmap::Options options, const QQuickImageProviderOptions &providerOptions) +void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &requestSize, QQuickPixmap::Options options, const QQuickImageProviderOptions &providerOptions, int frame, int frameCount) { if (d) { d->declarativePixmaps.remove(this); @@ -1562,7 +1585,7 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques d = nullptr; } - QQuickPixmapKey key = { &url, &requestSize, providerOptions }; + QQuickPixmapKey key = { &url, &requestSize, frame, providerOptions }; QQuickPixmapStore *store = pixmapStore(); QHash::Iterator iter = store->m_cache.end(); @@ -1574,7 +1597,7 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques QSize dummy; if (requestSize != dummy) qWarning() << "Ignoring sourceSize request for image url that came from grabToImage. Use the targetSize parameter of the grabToImage() function instead."; - const QQuickPixmapKey grabberKey = { &url, &dummy, QQuickImageProviderOptions() }; + const QQuickPixmapKey grabberKey = { &url, &dummy, 0, QQuickImageProviderOptions() }; iter = store->m_cache.find(grabberKey); } else if (options & QQuickPixmap::Cache) iter = store->m_cache.find(key); @@ -1596,7 +1619,7 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques if (!(options & QQuickPixmap::Asynchronous)) { bool ok = false; PIXMAP_PROFILE(pixmapStateChanged(url)); - d = createPixmapDataSync(this, engine, url, requestSize, providerOptions, &ok); + d = createPixmapDataSync(this, engine, url, requestSize, providerOptions, frame, &ok); if (ok) { PIXMAP_PROFILE(pixmapLoadingFinished(url, QSize(width(), height()))); if (options & QQuickPixmap::Cache) @@ -1613,7 +1636,7 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques return; - d = new QQuickPixmapData(this, url, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform); + d = new QQuickPixmapData(this, url, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform, frame, frameCount); if (options & QQuickPixmap::Cache) d->addToCache(); @@ -1647,9 +1670,9 @@ void QQuickPixmap::clear(QObject *obj) } } -bool QQuickPixmap::isCached(const QUrl &url, const QSize &requestSize, const QQuickImageProviderOptions &options) +bool QQuickPixmap::isCached(const QUrl &url, const QSize &requestSize, const int frame, const QQuickImageProviderOptions &options) { - QQuickPixmapKey key = { &url, &requestSize, options }; + QQuickPixmapKey key = { &url, &requestSize, frame, options }; QQuickPixmapStore *store = pixmapStore(); return store->m_cache.contains(key); diff --git a/src/quick/util/qquickpixmapcache_p.h b/src/quick/util/qquickpixmapcache_p.h index 91fb1ed3bb..ab5d391fa2 100644 --- a/src/quick/util/qquickpixmapcache_p.h +++ b/src/quick/util/qquickpixmapcache_p.h @@ -150,6 +150,7 @@ public: const QSize &implicitSize() const; const QSize &requestSize() const; QQuickImageProviderOptions::AutoTransform autoTransform() const; + int frameCount() const; QImage image() const; void setImage(const QImage &); void setPixmap(const QQuickPixmap &other); @@ -164,7 +165,7 @@ public: void load(QQmlEngine *, const QUrl &, QQuickPixmap::Options options); void load(QQmlEngine *, const QUrl &, const QSize &); void load(QQmlEngine *, const QUrl &, const QSize &, QQuickPixmap::Options options); - void load(QQmlEngine *, const QUrl &, const QSize &, QQuickPixmap::Options options, const QQuickImageProviderOptions &providerOptions); + void load(QQmlEngine *, const QUrl &, const QSize &, QQuickPixmap::Options options, const QQuickImageProviderOptions &providerOptions, int frame = 0, int frameCount = 1); void clear(); void clear(QObject *); @@ -175,7 +176,7 @@ public: bool connectDownloadProgress(QObject *, int); static void purgeCache(); - static bool isCached(const QUrl &url, const QSize &requestSize, const QQuickImageProviderOptions &options); + static bool isCached(const QUrl &url, const QSize &requestSize, const int frame, const QQuickImageProviderOptions &options); static const QLatin1String itemGrabberScheme; diff --git a/tests/auto/quick/qquickborderimage/data/multi.ico b/tests/auto/quick/qquickborderimage/data/multi.ico new file mode 100644 index 0000000000..b748ceaa29 Binary files /dev/null and b/tests/auto/quick/qquickborderimage/data/multi.ico differ diff --git a/tests/auto/quick/qquickborderimage/data/multiframe.qml b/tests/auto/quick/qquickborderimage/data/multiframe.qml new file mode 100644 index 0000000000..8bd32da5a6 --- /dev/null +++ b/tests/auto/quick/qquickborderimage/data/multiframe.qml @@ -0,0 +1,8 @@ +import QtQuick 2.14 + +BorderImage { + source: "multi.ico" + border { left: 19; top: 19; right: 19; bottom: 19 } + width: 160; height: 160 + horizontalTileMode: BorderImage.Stretch +} diff --git a/tests/auto/quick/qquickborderimage/data/multiframeAsync.qml b/tests/auto/quick/qquickborderimage/data/multiframeAsync.qml new file mode 100644 index 0000000000..059e4becf3 --- /dev/null +++ b/tests/auto/quick/qquickborderimage/data/multiframeAsync.qml @@ -0,0 +1,9 @@ +import QtQuick 2.14 + +BorderImage { + source: "multi.ico" + asynchronous: true + border { left: 19; top: 19; right: 19; bottom: 19 } + width: 160; height: 160 + horizontalTileMode: BorderImage.Stretch +} diff --git a/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp b/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp index 9292e1886a..4181f46551 100644 --- a/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp +++ b/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp @@ -79,6 +79,8 @@ private slots: #if QT_CONFIG(opengl) void borderImageMesh(); #endif + void multiFrame_data(); + void multiFrame(); private: QQmlEngine engine; @@ -601,6 +603,57 @@ void tst_qquickborderimage::borderImageMesh() qPrintable(errorMessage)); } #endif + +void tst_qquickborderimage::multiFrame_data() +{ + QTest::addColumn("qmlfile"); + QTest::addColumn("asynchronous"); + + QTest::addRow("default") << "multiframe.qml" << false; + QTest::addRow("async") << "multiframeAsync.qml" << true; +} + +void tst_qquickborderimage::multiFrame() +{ + QFETCH(QString, qmlfile); + QFETCH(bool, asynchronous); + Q_UNUSED(asynchronous) + + QQuickView view(testFileUrl(qmlfile)); + QQuickBorderImage *image = qobject_cast(view.rootObject()); + QVERIFY(image); + QSignalSpy countSpy(image, SIGNAL(frameCountChanged())); + QSignalSpy currentSpy(image, SIGNAL(currentFrameChanged())); + if (asynchronous) { + QCOMPARE(image->frameCount(), 0); + QTRY_COMPARE(image->frameCount(), 4); + QCOMPARE(countSpy.count(), 1); + } else { + QCOMPARE(image->frameCount(), 4); + } + QCOMPARE(image->currentFrame(), 0); + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + QImage contents = view.grabWindow(); + // The first frame looks blue, approximately qRgba(0x43, 0x7e, 0xd6, 0xff) + QRgb color = contents.pixel(60, 60); + QVERIFY(qRed(color) < 0xc0); + QVERIFY(qGreen(color) < 0xc0); + QVERIFY(qBlue(color) > 0xc0); + + image->setCurrentFrame(1); + QTRY_COMPARE(image->status(), QQuickImageBase::Ready); + QCOMPARE(currentSpy.count(), 1); + QCOMPARE(image->currentFrame(), 1); + contents = view.grabWindow(); + // The second frame looks green, approximately qRgba(0x3a, 0xd2, 0x31, 0xff) + color = contents.pixel(60, 60); + QVERIFY(qRed(color) < 0xc0); + QVERIFY(qGreen(color) > 0xc0); + QVERIFY(qBlue(color) < 0xc0); +} + QTEST_MAIN(tst_qquickborderimage) #include "tst_qquickborderimage.moc" diff --git a/tests/auto/quick/qquickimage/data/multi.ico b/tests/auto/quick/qquickimage/data/multi.ico new file mode 100644 index 0000000000..b748ceaa29 Binary files /dev/null and b/tests/auto/quick/qquickimage/data/multi.ico differ diff --git a/tests/auto/quick/qquickimage/data/multiframe.qml b/tests/auto/quick/qquickimage/data/multiframe.qml new file mode 100644 index 0000000000..df70bc784c --- /dev/null +++ b/tests/auto/quick/qquickimage/data/multiframe.qml @@ -0,0 +1,5 @@ +import QtQuick 2.14 + +Image { + source: "multi.ico" +} diff --git a/tests/auto/quick/qquickimage/data/multiframeAsync.qml b/tests/auto/quick/qquickimage/data/multiframeAsync.qml new file mode 100644 index 0000000000..167b4a3e57 --- /dev/null +++ b/tests/auto/quick/qquickimage/data/multiframeAsync.qml @@ -0,0 +1,6 @@ +import QtQuick 2.14 + +Image { + source: "multi.ico" + asynchronous: true +} diff --git a/tests/auto/quick/qquickimage/tst_qquickimage.cpp b/tests/auto/quick/qquickimage/tst_qquickimage.cpp index 34c18aa64b..23635590e4 100644 --- a/tests/auto/quick/qquickimage/tst_qquickimage.cpp +++ b/tests/auto/quick/qquickimage/tst_qquickimage.cpp @@ -97,6 +97,8 @@ private slots: void highDpiFillModesAndSizes(); void hugeImages(); void urlInterceptor(); + void multiFrame_data(); + void multiFrame(); private: QQmlEngine engine; @@ -1132,6 +1134,56 @@ void tst_qquickimage::urlInterceptor() QTRY_COMPARE(object->progress(), 1.0); } +void tst_qquickimage::multiFrame_data() +{ + QTest::addColumn("qmlfile"); + QTest::addColumn("asynchronous"); + + QTest::addRow("default") << "multiframe.qml" << false; + QTest::addRow("async") << "multiframeAsync.qml" << true; +} + +void tst_qquickimage::multiFrame() +{ + QFETCH(QString, qmlfile); + QFETCH(bool, asynchronous); + Q_UNUSED(asynchronous) + + QQuickView view(testFileUrl(qmlfile)); + QQuickImage *image = qobject_cast(view.rootObject()); + QVERIFY(image); + QSignalSpy countSpy(image, SIGNAL(frameCountChanged())); + QSignalSpy currentSpy(image, SIGNAL(currentFrameChanged())); + if (asynchronous) { + QCOMPARE(image->frameCount(), 0); + QTRY_COMPARE(image->frameCount(), 4); + QCOMPARE(countSpy.count(), 1); + } else { + QCOMPARE(image->frameCount(), 4); + } + QCOMPARE(image->currentFrame(), 0); + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + QImage contents = view.grabWindow(); + // The first frame is a blue ball, approximately qRgba(0x33, 0x6d, 0xcc, 0xff) + QRgb color = contents.pixel(16, 16); + QVERIFY(qRed(color) < 0xc0); + QVERIFY(qGreen(color) < 0xc0); + QVERIFY(qBlue(color) > 0xc0); + + image->setCurrentFrame(1); + QTRY_COMPARE(image->status(), QQuickImageBase::Ready); + QCOMPARE(currentSpy.count(), 1); + QCOMPARE(image->currentFrame(), 1); + contents = view.grabWindow(); + // The second frame is a green ball, approximately qRgba(0x27, 0xc8, 0x22, 0xff) + color = contents.pixel(16, 16); + QVERIFY(qRed(color) < 0xc0); + QVERIFY(qGreen(color) > 0xc0); + QVERIFY(qBlue(color) < 0xc0); +} + QTEST_MAIN(tst_qquickimage) #include "tst_qquickimage.moc" -- cgit v1.2.3 From 826177eccab7ee3ac16b456bc57c0f271da14507 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 23 Aug 2019 18:27:59 +0200 Subject: Stabilize image and borderimage multiFrame tests There are various problems on QEMU: color depth may not be 32-bit, and for some reason grabWindow isn't always working. Task-number: QTBUG-77817 Change-Id: I10db56e93643722d1d6a85e66b9dd552ee654432 Reviewed-by: Shawn Rutledge --- .../qquickborderimage/tst_qquickborderimage.cpp | 32 +++++++++++++++------- tests/auto/quick/qquickimage/tst_qquickimage.cpp | 6 ++++ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp b/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp index 4181f46551..dc3a783600 100644 --- a/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp +++ b/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp @@ -46,6 +46,8 @@ #include "../../shared/util.h" #include "../shared/visualtestutil.h" +Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests") + Q_DECLARE_METATYPE(QQuickImageBase::Status) class tst_qquickborderimage : public QQmlDataTest @@ -615,6 +617,10 @@ void tst_qquickborderimage::multiFrame_data() void tst_qquickborderimage::multiFrame() { + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); + QFETCH(QString, qmlfile); QFETCH(bool, asynchronous); Q_UNUSED(asynchronous) @@ -634,24 +640,30 @@ void tst_qquickborderimage::multiFrame() QCOMPARE(image->currentFrame(), 0); view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); + QCoreApplication::processEvents(); // Process all queued events QImage contents = view.grabWindow(); - // The first frame looks blue, approximately qRgba(0x43, 0x7e, 0xd6, 0xff) - QRgb color = contents.pixel(60, 60); - QVERIFY(qRed(color) < 0xc0); - QVERIFY(qGreen(color) < 0xc0); - QVERIFY(qBlue(color) > 0xc0); + if (contents.width() < 160) + QSKIP("Skipping due to grabWindow not functional"); + + // The middle of the first frame looks blue, approximately qRgba(0x43, 0x7e, 0xd6, 0xff) + QColor color = contents.pixelColor(60, 60); + qCDebug(lcTests) << "expected bluish color, got" << color; + QVERIFY(color.redF() < 0.75); + QVERIFY(color.greenF() < 0.75); + QVERIFY(color.blueF() > 0.75); image->setCurrentFrame(1); QTRY_COMPARE(image->status(), QQuickImageBase::Ready); QCOMPARE(currentSpy.count(), 1); QCOMPARE(image->currentFrame(), 1); contents = view.grabWindow(); - // The second frame looks green, approximately qRgba(0x3a, 0xd2, 0x31, 0xff) - color = contents.pixel(60, 60); - QVERIFY(qRed(color) < 0xc0); - QVERIFY(qGreen(color) > 0xc0); - QVERIFY(qBlue(color) < 0xc0); + // The middle of the second frame looks green, approximately qRgba(0x3a, 0xd2, 0x31, 0xff) + color = contents.pixelColor(60, 60); + qCDebug(lcTests) << "expected greenish color, got" << color; + QVERIFY(color.redF() < 0.75); + QVERIFY(color.green() > 0.75); + QVERIFY(color.blueF() < 0.75); } QTEST_MAIN(tst_qquickborderimage) diff --git a/tests/auto/quick/qquickimage/tst_qquickimage.cpp b/tests/auto/quick/qquickimage/tst_qquickimage.cpp index 23635590e4..abc7cd86bd 100644 --- a/tests/auto/quick/qquickimage/tst_qquickimage.cpp +++ b/tests/auto/quick/qquickimage/tst_qquickimage.cpp @@ -1145,6 +1145,10 @@ void tst_qquickimage::multiFrame_data() void tst_qquickimage::multiFrame() { + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); + QFETCH(QString, qmlfile); QFETCH(bool, asynchronous); Q_UNUSED(asynchronous) @@ -1166,6 +1170,8 @@ void tst_qquickimage::multiFrame() QVERIFY(QTest::qWaitForWindowExposed(&view)); QImage contents = view.grabWindow(); + if (contents.width() < 40) + QSKIP("Skipping due to grabWindow not functional"); // The first frame is a blue ball, approximately qRgba(0x33, 0x6d, 0xcc, 0xff) QRgb color = contents.pixel(16, 16); QVERIFY(qRed(color) < 0xc0); -- cgit v1.2.3 From 5c04f14e4cdb64eb89532491dcf09e27c5fe29ac Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 26 Aug 2019 15:25:58 +0200 Subject: QQuickPinch: Declare notify signal for target This way we can figure out from the metaobject that this signal actually notifies about target changes. Change-Id: I2151990e906e375f807b2d952e8f183a19529394 Reviewed-by: Fabian Kosmale Reviewed-by: Simon Hausmann Reviewed-by: Shawn Rutledge --- src/quick/items/qquickpincharea_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quick/items/qquickpincharea_p.h b/src/quick/items/qquickpincharea_p.h index 8eff53e6dc..579a3ce27c 100644 --- a/src/quick/items/qquickpincharea_p.h +++ b/src/quick/items/qquickpincharea_p.h @@ -59,7 +59,7 @@ class Q_AUTOTEST_EXPORT QQuickPinch : public QObject { Q_OBJECT - Q_PROPERTY(QQuickItem *target READ target WRITE setTarget RESET resetTarget) + Q_PROPERTY(QQuickItem *target READ target WRITE setTarget RESET resetTarget NOTIFY targetChanged) Q_PROPERTY(qreal minimumScale READ minimumScale WRITE setMinimumScale NOTIFY minimumScaleChanged) Q_PROPERTY(qreal maximumScale READ maximumScale WRITE setMaximumScale NOTIFY maximumScaleChanged) Q_PROPERTY(qreal minimumRotation READ minimumRotation WRITE setMinimumRotation NOTIFY minimumRotationChanged) -- cgit v1.2.3 From 69dcabed60208c6e6226b52332bf4ab5b107130d Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 16 Aug 2019 13:11:53 +0200 Subject: Make the qmllint test an actual test Change-Id: I59a96cbef9a68454b68a37e5c7aed45cb4009785 Reviewed-by: Fabian Kosmale Reviewed-by: Simon Hausmann --- tests/auto/qml/qmllint/main.cpp | 175 --------------------------------- tests/auto/qml/qmllint/qmllint.pro | 13 ++- tests/auto/qml/qmllint/tst_qmllint.cpp | 174 ++++++++++++++++++++++++++++++++ 3 files changed, 183 insertions(+), 179 deletions(-) delete mode 100644 tests/auto/qml/qmllint/main.cpp create mode 100644 tests/auto/qml/qmllint/tst_qmllint.cpp diff --git a/tests/auto/qml/qmllint/main.cpp b/tests/auto/qml/qmllint/main.cpp deleted file mode 100644 index 87b34d83bd..0000000000 --- a/tests/auto/qml/qmllint/main.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Sergio Martins -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins 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 -#include -#include - -class TestQmllint: public QObject -{ - Q_OBJECT - -private Q_SLOTS: - void initTestCase(); - void test(); - void test_data(); - void testUnqualified(); - void testUnqualified_data(); - void testUnqualifiedNoSpuriousParentWarning(); - void catchIdentifierNoFalsePositive(); -private: - QString m_qmllintPath; -}; - -void TestQmllint::initTestCase() -{ - m_qmllintPath = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QLatin1String("/qmllint"); -#ifdef Q_OS_WIN - m_qmllintPath += QLatin1String(".exe"); -#endif - if (!QFileInfo(m_qmllintPath).exists()) { - QString message = QStringLiteral("qmllint executable not found (looked for %0)").arg(m_qmllintPath); - QFAIL(qPrintable(message)); - } -} - -void TestQmllint::test_data() -{ - QTest::addColumn("filename"); - QTest::addColumn("isValid"); - - // Valid files: - QTest::newRow("Simple_QML") << QStringLiteral("Simple.qml") << true; - QTest::newRow("QML_importing_JS") << QStringLiteral("importing_js.qml") << true; - QTest::newRow("QTBUG-45916_JS_with_pragma_and_import") << QStringLiteral("QTBUG-45916.js") << true; - - // Invalid files: - QTest::newRow("Invalid_syntax_QML") << QStringLiteral("failure1.qml") << false; - QTest::newRow("Invalid_syntax_JS") << QStringLiteral("failure1.js") << false; -} - -void TestQmllint::testUnqualified() -{ - auto qmlImportDir = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath); - QFETCH(QString, filename); - QFETCH(QString, warningMessage); - QFETCH(int, warningLine); - QFETCH(int, warningColumn); - filename.prepend(QStringLiteral("data/")); - QStringList args; - args << QStringLiteral("-U") << filename << QStringLiteral("-I") << qmlImportDir; - - QProcess process; - process.start(m_qmllintPath, args); - QVERIFY(process.waitForFinished()); - QVERIFY(process.exitStatus() == QProcess::NormalExit); - QVERIFY(process.exitCode()); - QString output = process.readAllStandardError(); - QVERIFY(output.contains(QString::asprintf("Warning: unqualified access at %d:%d", warningLine, warningColumn))); - QVERIFY(output.contains(warningMessage)); -} - -void TestQmllint::testUnqualified_data() -{ - QTest::addColumn("filename"); - QTest::addColumn("warningMessage"); - QTest::addColumn("warningLine"); - QTest::addColumn("warningColumn"); - - // check for false positive due to and warning about with statement - QTest::newRow("WithStatement") << QStringLiteral("WithStatement.qml") << QStringLiteral("with statements are strongly discouraged") << 10 << 25; - // id from nowhere (as with setContextProperty) - QTest::newRow("IdFromOuterSpaceDirect") << QStringLiteral("IdFromOuterSpace.qml") << "alien.x" << 4 << 8; - QTest::newRow("IdFromOuterSpaceAccess") << QStringLiteral("IdFromOuterSpace.qml") << "console.log(alien)" << 7 << 21; - // access property of root object - QTest::newRow("FromRootDirect") << QStringLiteral("FromRoot.qml") << QStringLiteral("x: root.unqualified") << 9 << 16; // new property - QTest::newRow("FromRootAccess") << QStringLiteral("FromRoot.qml") << QStringLiteral("property int check: root.x") << 13 << 33; // builtin property - // access injected name from signal - QTest::newRow("SignalHandler1") << QStringLiteral("SignalHandler.qml") << QStringLiteral("onDoubleClicked: function(mouse) {...") << 5 << 21; - QTest::newRow("SignalHandler2") << QStringLiteral("SignalHandler.qml") << QStringLiteral("onPositionChanged: function(mouse) {...") << 10 << 21; - QTest::newRow("SignalHandlerShort1") << QStringLiteral("SignalHandler.qml") << QStringLiteral("onClicked: (mouse) => {...") << 8 << 29; - QTest::newRow("SignalHandlerShort2") << QStringLiteral("SignalHandler.qml") << QStringLiteral("onPressAndHold: (mouse) => {...") << 12 << 34; - // access catch identifier outside catch block - QTest::newRow("CatchStatement") << QStringLiteral("CatchStatement.qml") << QStringLiteral("err") << 6 << 21; -} - -void TestQmllint::testUnqualifiedNoSpuriousParentWarning() -{ - auto qmlImportDir = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath); - { - QString filename = QLatin1String("spuriousParentWarning.qml"); - filename.prepend(QStringLiteral("data/")); - QStringList args; - args << QStringLiteral("-U") << filename << QStringLiteral("-I") << qmlImportDir; - QProcess process; - process.start(m_qmllintPath, args); - QVERIFY(process.waitForFinished()); - QVERIFY(process.exitStatus() == QProcess::NormalExit); - QVERIFY(process.exitCode() == 0); - } - { - QString filename = QLatin1String("nonSpuriousParentWarning.qml"); - filename.prepend(QStringLiteral("data/")); - QStringList args; - args << QStringLiteral("-U") << filename << QStringLiteral("-I") << qmlImportDir; - QProcess process; - process.start(m_qmllintPath, args); - QVERIFY(process.waitForFinished()); - QVERIFY(process.exitStatus() == QProcess::NormalExit); - QVERIFY(process.exitCode()); - } -} - -void TestQmllint::catchIdentifierNoFalsePositive() -{ - auto qmlImportDir = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath); - QString filename = QLatin1String("catchIdentifierNoWarning.qml"); - filename.prepend(QStringLiteral("data/")); - QStringList args; - args << QStringLiteral("-U") << filename << QStringLiteral("-I") << qmlImportDir; - QProcess process; - process.start(m_qmllintPath, args); - QVERIFY(process.waitForFinished()); - QVERIFY(process.exitStatus() == QProcess::NormalExit); - QVERIFY(process.exitCode() == 0); -} - -void TestQmllint::test() -{ - QFETCH(QString, filename); - QFETCH(bool, isValid); - filename = QStringLiteral("data/") + filename; - QStringList args; - args << QStringLiteral("--silent") << filename; - - bool success = QProcess::execute(m_qmllintPath, args) == 0; - QCOMPARE(success, isValid); -} - -QTEST_MAIN(TestQmllint) -#include "main.moc" diff --git a/tests/auto/qml/qmllint/qmllint.pro b/tests/auto/qml/qmllint/qmllint.pro index b53a6f6877..95470b4085 100644 --- a/tests/auto/qml/qmllint/qmllint.pro +++ b/tests/auto/qml/qmllint/qmllint.pro @@ -1,6 +1,11 @@ -TEMPLATE = app -TARGET = testqmllint -INCLUDEPATH += . +CONFIG += testcase +TARGET = tst_qmllint +macos:CONFIG -= app_bundle + +SOURCES += tst_qmllint.cpp + +include (../../shared/util.pri) + +TESTDATA = data/* -SOURCES += main.cpp QT += testlib diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp new file mode 100644 index 0000000000..582f146dca --- /dev/null +++ b/tests/auto/qml/qmllint/tst_qmllint.cpp @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Sergio Martins +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins 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 +#include +#include + +#include + +class TestQmllint: public QQmlDataTest +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase() override; + void test(); + void test_data(); + void testUnqualified(); + void testUnqualified_data(); + void testUnqualifiedNoSpuriousParentWarning(); + void catchIdentifierNoFalsePositive(); +private: + QString m_qmllintPath; +}; + +void TestQmllint::initTestCase() +{ + QQmlDataTest::initTestCase(); + m_qmllintPath = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QLatin1String("/qmllint"); +#ifdef Q_OS_WIN + m_qmllintPath += QLatin1String(".exe"); +#endif + if (!QFileInfo(m_qmllintPath).exists()) { + QString message = QStringLiteral("qmllint executable not found (looked for %0)").arg(m_qmllintPath); + QFAIL(qPrintable(message)); + } +} + +void TestQmllint::test_data() +{ + QTest::addColumn("filename"); + QTest::addColumn("isValid"); + + // Valid files: + QTest::newRow("Simple_QML") << QStringLiteral("Simple.qml") << true; + QTest::newRow("QML_importing_JS") << QStringLiteral("importing_js.qml") << true; + QTest::newRow("QTBUG-45916_JS_with_pragma_and_import") << QStringLiteral("QTBUG-45916.js") << true; + + // Invalid files: + QTest::newRow("Invalid_syntax_QML") << QStringLiteral("failure1.qml") << false; + QTest::newRow("Invalid_syntax_JS") << QStringLiteral("failure1.js") << false; +} + +void TestQmllint::testUnqualified() +{ + auto qmlImportDir = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath); + QFETCH(QString, filename); + QFETCH(QString, warningMessage); + QFETCH(int, warningLine); + QFETCH(int, warningColumn); + QStringList args; + args << QStringLiteral("-U") << testFile(filename) << QStringLiteral("-I") << qmlImportDir; + + QProcess process; + process.start(m_qmllintPath, args); + QVERIFY(process.waitForFinished()); + QVERIFY(process.exitStatus() == QProcess::NormalExit); + QVERIFY(process.exitCode()); + QString output = process.readAllStandardError(); + QVERIFY(output.contains(QString::asprintf("Warning: unqualified access at %d:%d", warningLine, warningColumn))); + QVERIFY(output.contains(warningMessage)); +} + +void TestQmllint::testUnqualified_data() +{ + QTest::addColumn("filename"); + QTest::addColumn("warningMessage"); + QTest::addColumn("warningLine"); + QTest::addColumn("warningColumn"); + + // check for false positive due to and warning about with statement + QTest::newRow("WithStatement") << QStringLiteral("WithStatement.qml") << QStringLiteral("with statements are strongly discouraged") << 10 << 25; + // id from nowhere (as with setContextProperty) + QTest::newRow("IdFromOuterSpaceDirect") << QStringLiteral("IdFromOuterSpace.qml") << "alien.x" << 4 << 8; + QTest::newRow("IdFromOuterSpaceAccess") << QStringLiteral("IdFromOuterSpace.qml") << "console.log(alien)" << 7 << 21; + // access property of root object + QTest::newRow("FromRootDirect") << QStringLiteral("FromRoot.qml") << QStringLiteral("x: root.unqualified") << 9 << 16; // new property + QTest::newRow("FromRootAccess") << QStringLiteral("FromRoot.qml") << QStringLiteral("property int check: root.x") << 13 << 33; // builtin property + // access injected name from signal + QTest::newRow("SignalHandler1") << QStringLiteral("SignalHandler.qml") << QStringLiteral("onDoubleClicked: function(mouse) {...") << 5 << 21; + QTest::newRow("SignalHandler2") << QStringLiteral("SignalHandler.qml") << QStringLiteral("onPositionChanged: function(mouse) {...") << 10 << 21; + QTest::newRow("SignalHandlerShort1") << QStringLiteral("SignalHandler.qml") << QStringLiteral("onClicked: (mouse) => {...") << 8 << 29; + QTest::newRow("SignalHandlerShort2") << QStringLiteral("SignalHandler.qml") << QStringLiteral("onPressAndHold: (mouse) => {...") << 12 << 34; + // access catch identifier outside catch block + QTest::newRow("CatchStatement") << QStringLiteral("CatchStatement.qml") << QStringLiteral("err") << 6 << 21; +} + +void TestQmllint::testUnqualifiedNoSpuriousParentWarning() +{ + auto qmlImportDir = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath); + { + QString filename = testFile("spuriousParentWarning.qml"); + QStringList args; + args << QStringLiteral("-U") << filename << QStringLiteral("-I") << qmlImportDir; + QProcess process; + process.start(m_qmllintPath, args); + QVERIFY(process.waitForFinished()); + QVERIFY(process.exitStatus() == QProcess::NormalExit); + QVERIFY(process.exitCode() == 0); + } + { + QString filename = testFile("nonSpuriousParentWarning.qml"); + QStringList args; + args << QStringLiteral("-U") << filename << QStringLiteral("-I") << qmlImportDir; + QProcess process; + process.start(m_qmllintPath, args); + QVERIFY(process.waitForFinished()); + QVERIFY(process.exitStatus() == QProcess::NormalExit); + QVERIFY(process.exitCode()); + } +} + +void TestQmllint::catchIdentifierNoFalsePositive() +{ + auto qmlImportDir = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath); + QString filename = QLatin1String("catchIdentifierNoWarning.qml"); + filename.prepend(QStringLiteral("data/")); + QStringList args; + args << QStringLiteral("-U") << filename << QStringLiteral("-I") << qmlImportDir; + QProcess process; + process.start(m_qmllintPath, args); + QVERIFY(process.waitForFinished()); + QVERIFY(process.exitStatus() == QProcess::NormalExit); + QVERIFY(process.exitCode() == 0); +} + +void TestQmllint::test() +{ + QFETCH(QString, filename); + QFETCH(bool, isValid); + QStringList args; + args << QStringLiteral("--silent") << testFile(filename); + + bool success = QProcess::execute(m_qmllintPath, args) == 0; + QCOMPARE(success, isValid); +} + +QTEST_MAIN(TestQmllint) +#include "tst_qmllint.moc" -- cgit v1.2.3 From 6b3f5442641ee53dffc5b7e8ea8679d66668d114 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 21 Aug 2019 18:04:04 +0200 Subject: Regenerate plugins.qmltypes Change-Id: I9e470d08ee93c44663e6f99cebe7817c90cba3e4 Reviewed-by: Simon Hausmann Reviewed-by: Shawn Rutledge --- src/imports/builtins/builtins.qmltypes | 13 +- src/imports/folderlistmodel/plugins.qmltypes | 2 +- src/imports/labsmodels/plugins.qmltypes | 373 +++++++++++++++++++++++++++ src/imports/layouts/plugins.qmltypes | 2 +- src/imports/localstorage/plugins.qmltypes | 2 +- src/imports/models/plugins.qmltypes | 75 +++++- src/imports/particles/plugins.qmltypes | 10 +- src/imports/qtqml/dependencies.json | 2 + src/imports/qtqml/plugins.qmltypes | 24 +- src/imports/qtquick2/plugins.qmltypes | 169 ++++++++++-- src/imports/shapes/plugins.qmltypes | 10 +- src/imports/statemachine/plugins.qmltypes | 2 +- src/imports/testlib/plugins.qmltypes | 8 +- src/imports/wavefrontmesh/plugins.qmltypes | 2 +- src/imports/window/plugins.qmltypes | 4 +- src/imports/workerscript/plugins.qmltypes | 26 ++ 16 files changed, 677 insertions(+), 47 deletions(-) create mode 100644 src/imports/qtqml/dependencies.json create mode 100644 src/imports/workerscript/plugins.qmltypes diff --git a/src/imports/builtins/builtins.qmltypes b/src/imports/builtins/builtins.qmltypes index 4ad103f8de..c783c63caf 100644 --- a/src/imports/builtins/builtins.qmltypes +++ b/src/imports/builtins/builtins.qmltypes @@ -130,6 +130,13 @@ Module { "DescendingOrder": 1 } } + Enum { + name: "SplitBehavior" + values: { + "KeepEmptyParts": 0, + "SkipEmptyParts": 1 + } + } Enum { name: "Alignment" values: { @@ -466,7 +473,8 @@ Module { "AA_DontShowShortcutsInContextMenus": 28, "AA_CompressTabletEvents": 29, "AA_DisableWindowContextHelpButton": 30, - "AA_AttributeCount": 31 + "AA_DisableSessionManager": 31, + "AA_AttributeCount": 32 } } Enum { @@ -1081,7 +1089,8 @@ Module { values: { "PlainText": 0, "RichText": 1, - "AutoText": 2 + "AutoText": 2, + "MarkdownText": 3 } } Enum { diff --git a/src/imports/folderlistmodel/plugins.qmltypes b/src/imports/folderlistmodel/plugins.qmltypes index 6f5466dbda..0fdbae66d3 100644 --- a/src/imports/folderlistmodel/plugins.qmltypes +++ b/src/imports/folderlistmodel/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable Qt.labs.folderlistmodel 2.13' +// 'qmlplugindump -nonrelocatable Qt.labs.folderlistmodel 2.14' Module { dependencies: ["QtQuick 2.0"] diff --git a/src/imports/labsmodels/plugins.qmltypes b/src/imports/labsmodels/plugins.qmltypes index 6272069060..f2a5752422 100644 --- a/src/imports/labsmodels/plugins.qmltypes +++ b/src/imports/labsmodels/plugins.qmltypes @@ -8,6 +8,280 @@ import QtQuick.tooling 1.2 Module { dependencies: [] + Component { + name: "QAbstractItemModel" + prototype: "QObject" + Enum { + name: "LayoutChangeHint" + values: { + "NoLayoutChangeHint": 0, + "VerticalSortHint": 1, + "HorizontalSortHint": 2 + } + } + Enum { + name: "CheckIndexOption" + values: { + "NoOption": 0, + "IndexIsValid": 1, + "DoNotUseParent": 2, + "ParentIsInvalid": 4 + } + } + Signal { + name: "dataChanged" + Parameter { name: "topLeft"; type: "QModelIndex" } + Parameter { name: "bottomRight"; type: "QModelIndex" } + Parameter { name: "roles"; type: "QVector" } + } + Signal { + name: "dataChanged" + Parameter { name: "topLeft"; type: "QModelIndex" } + Parameter { name: "bottomRight"; type: "QModelIndex" } + } + Signal { + name: "headerDataChanged" + Parameter { name: "orientation"; type: "Qt::Orientation" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { + name: "layoutChanged" + Parameter { name: "parents"; type: "QList" } + Parameter { name: "hint"; type: "QAbstractItemModel::LayoutChangeHint" } + } + Signal { + name: "layoutChanged" + Parameter { name: "parents"; type: "QList" } + } + Signal { name: "layoutChanged" } + Signal { + name: "layoutAboutToBeChanged" + Parameter { name: "parents"; type: "QList" } + Parameter { name: "hint"; type: "QAbstractItemModel::LayoutChangeHint" } + } + Signal { + name: "layoutAboutToBeChanged" + Parameter { name: "parents"; type: "QList" } + } + Signal { name: "layoutAboutToBeChanged" } + Signal { + name: "rowsAboutToBeInserted" + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { + name: "rowsInserted" + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { + name: "rowsAboutToBeRemoved" + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { + name: "rowsRemoved" + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { + name: "columnsAboutToBeInserted" + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { + name: "columnsInserted" + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { + name: "columnsAboutToBeRemoved" + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { + name: "columnsRemoved" + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { name: "modelAboutToBeReset" } + Signal { name: "modelReset" } + Signal { + name: "rowsAboutToBeMoved" + Parameter { name: "sourceParent"; type: "QModelIndex" } + Parameter { name: "sourceStart"; type: "int" } + Parameter { name: "sourceEnd"; type: "int" } + Parameter { name: "destinationParent"; type: "QModelIndex" } + Parameter { name: "destinationRow"; type: "int" } + } + Signal { + name: "rowsMoved" + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "start"; type: "int" } + Parameter { name: "end"; type: "int" } + Parameter { name: "destination"; type: "QModelIndex" } + Parameter { name: "row"; type: "int" } + } + Signal { + name: "columnsAboutToBeMoved" + Parameter { name: "sourceParent"; type: "QModelIndex" } + Parameter { name: "sourceStart"; type: "int" } + Parameter { name: "sourceEnd"; type: "int" } + Parameter { name: "destinationParent"; type: "QModelIndex" } + Parameter { name: "destinationColumn"; type: "int" } + } + Signal { + name: "columnsMoved" + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "start"; type: "int" } + Parameter { name: "end"; type: "int" } + Parameter { name: "destination"; type: "QModelIndex" } + Parameter { name: "column"; type: "int" } + } + Method { name: "submit"; type: "bool" } + Method { name: "revert" } + Method { + name: "hasIndex" + type: "bool" + Parameter { name: "row"; type: "int" } + Parameter { name: "column"; type: "int" } + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { + name: "hasIndex" + type: "bool" + Parameter { name: "row"; type: "int" } + Parameter { name: "column"; type: "int" } + } + Method { + name: "index" + type: "QModelIndex" + Parameter { name: "row"; type: "int" } + Parameter { name: "column"; type: "int" } + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { + name: "index" + type: "QModelIndex" + Parameter { name: "row"; type: "int" } + Parameter { name: "column"; type: "int" } + } + Method { + name: "parent" + type: "QModelIndex" + Parameter { name: "child"; type: "QModelIndex" } + } + Method { + name: "sibling" + type: "QModelIndex" + Parameter { name: "row"; type: "int" } + Parameter { name: "column"; type: "int" } + Parameter { name: "idx"; type: "QModelIndex" } + } + Method { + name: "rowCount" + type: "int" + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { name: "rowCount"; type: "int" } + Method { + name: "columnCount" + type: "int" + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { name: "columnCount"; type: "int" } + Method { + name: "hasChildren" + type: "bool" + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { name: "hasChildren"; type: "bool" } + Method { + name: "data" + type: "QVariant" + Parameter { name: "index"; type: "QModelIndex" } + Parameter { name: "role"; type: "int" } + } + Method { + name: "data" + type: "QVariant" + Parameter { name: "index"; type: "QModelIndex" } + } + Method { + name: "setData" + type: "bool" + Parameter { name: "index"; type: "QModelIndex" } + Parameter { name: "value"; type: "QVariant" } + Parameter { name: "role"; type: "int" } + } + Method { + name: "setData" + type: "bool" + Parameter { name: "index"; type: "QModelIndex" } + Parameter { name: "value"; type: "QVariant" } + } + Method { + name: "headerData" + type: "QVariant" + Parameter { name: "section"; type: "int" } + Parameter { name: "orientation"; type: "Qt::Orientation" } + Parameter { name: "role"; type: "int" } + } + Method { + name: "headerData" + type: "QVariant" + Parameter { name: "section"; type: "int" } + Parameter { name: "orientation"; type: "Qt::Orientation" } + } + Method { + name: "fetchMore" + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { + name: "canFetchMore" + type: "bool" + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { + name: "flags" + type: "Qt::ItemFlags" + Parameter { name: "index"; type: "QModelIndex" } + } + Method { + name: "match" + type: "QModelIndexList" + Parameter { name: "start"; type: "QModelIndex" } + Parameter { name: "role"; type: "int" } + Parameter { name: "value"; type: "QVariant" } + Parameter { name: "hits"; type: "int" } + Parameter { name: "flags"; type: "Qt::MatchFlags" } + } + Method { + name: "match" + type: "QModelIndexList" + Parameter { name: "start"; type: "QModelIndex" } + Parameter { name: "role"; type: "int" } + Parameter { name: "value"; type: "QVariant" } + Parameter { name: "hits"; type: "int" } + } + Method { + name: "match" + type: "QModelIndexList" + Parameter { name: "start"; type: "QModelIndex" } + Parameter { name: "role"; type: "int" } + Parameter { name: "value"; type: "QVariant" } + } + } + Component { name: "QAbstractTableModel"; prototype: "QAbstractItemModel" } Component { name: "QQmlAbstractDelegateComponent" prototype: "QQmlComponent" @@ -38,4 +312,103 @@ Module { Property { name: "role"; type: "string" } Property { name: "choices"; type: "QQmlDelegateChoice"; isList: true; isReadonly: true } } + Component { + name: "QQmlTableModel" + defaultProperty: "columns" + prototype: "QAbstractTableModel" + exports: ["Qt.labs.qmlmodels/TableModel 1.0"] + exportMetaObjectRevisions: [0] + Property { name: "columnCount"; type: "int"; isReadonly: true } + Property { name: "rowCount"; type: "int"; isReadonly: true } + Property { name: "rows"; type: "QVariant" } + Property { name: "columns"; type: "QQmlTableModelColumn"; isList: true; isReadonly: true } + Method { + name: "appendRow" + Parameter { name: "row"; type: "QVariant" } + } + Method { name: "clear" } + Method { + name: "getRow" + type: "QVariant" + Parameter { name: "rowIndex"; type: "int" } + } + Method { + name: "insertRow" + Parameter { name: "rowIndex"; type: "int" } + Parameter { name: "row"; type: "QVariant" } + } + Method { + name: "moveRow" + Parameter { name: "fromRowIndex"; type: "int" } + Parameter { name: "toRowIndex"; type: "int" } + Parameter { name: "rows"; type: "int" } + } + Method { + name: "moveRow" + Parameter { name: "fromRowIndex"; type: "int" } + Parameter { name: "toRowIndex"; type: "int" } + } + Method { + name: "removeRow" + Parameter { name: "rowIndex"; type: "int" } + Parameter { name: "rows"; type: "int" } + } + Method { + name: "removeRow" + Parameter { name: "rowIndex"; type: "int" } + } + Method { + name: "setRow" + Parameter { name: "rowIndex"; type: "int" } + Parameter { name: "row"; type: "QVariant" } + } + Method { + name: "data" + type: "QVariant" + Parameter { name: "index"; type: "QModelIndex" } + Parameter { name: "role"; type: "string" } + } + Method { + name: "setData" + type: "bool" + Parameter { name: "index"; type: "QModelIndex" } + Parameter { name: "role"; type: "string" } + Parameter { name: "value"; type: "QVariant" } + } + } + Component { + name: "QQmlTableModelColumn" + prototype: "QObject" + exports: ["Qt.labs.qmlmodels/TableModelColumn 1.0"] + exportMetaObjectRevisions: [0] + Property { name: "display"; type: "QJSValue" } + Property { name: "setDisplay"; type: "QJSValue" } + Property { name: "decoration"; type: "QJSValue" } + Property { name: "setDecoration"; type: "QJSValue" } + Property { name: "edit"; type: "QJSValue" } + Property { name: "setEdit"; type: "QJSValue" } + Property { name: "toolTip"; type: "QJSValue" } + Property { name: "setToolTip"; type: "QJSValue" } + Property { name: "statusTip"; type: "QJSValue" } + Property { name: "setStatusTip"; type: "QJSValue" } + Property { name: "whatsThis"; type: "QJSValue" } + Property { name: "setWhatsThis"; type: "QJSValue" } + Property { name: "font"; type: "QJSValue" } + Property { name: "setFont"; type: "QJSValue" } + Property { name: "textAlignment"; type: "QJSValue" } + Property { name: "setTextAlignment"; type: "QJSValue" } + Property { name: "background"; type: "QJSValue" } + Property { name: "setBackground"; type: "QJSValue" } + Property { name: "foreground"; type: "QJSValue" } + Property { name: "setForeground"; type: "QJSValue" } + Property { name: "checkState"; type: "QJSValue" } + Property { name: "setCheckState"; type: "QJSValue" } + Property { name: "accessibleText"; type: "QJSValue" } + Property { name: "setAccessibleText"; type: "QJSValue" } + Property { name: "accessibleDescription"; type: "QJSValue" } + Property { name: "setAccessibleDescription"; type: "QJSValue" } + Property { name: "sizeHint"; type: "QJSValue" } + Property { name: "setSizeHint"; type: "QJSValue" } + Signal { name: "indexChanged" } + } } diff --git a/src/imports/layouts/plugins.qmltypes b/src/imports/layouts/plugins.qmltypes index 22e8d79ece..6015164511 100644 --- a/src/imports/layouts/plugins.qmltypes +++ b/src/imports/layouts/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable QtQuick.Layouts 1.13' +// 'qmlplugindump -nonrelocatable QtQuick.Layouts 1.14' Module { dependencies: ["QtQuick 2.0"] diff --git a/src/imports/localstorage/plugins.qmltypes b/src/imports/localstorage/plugins.qmltypes index 3c8c1404f2..6ed334cc9d 100644 --- a/src/imports/localstorage/plugins.qmltypes +++ b/src/imports/localstorage/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQuick.LocalStorage 2.13' +// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQuick.LocalStorage 2.14' Module { dependencies: [] diff --git a/src/imports/models/plugins.qmltypes b/src/imports/models/plugins.qmltypes index 6e112c41b6..0d8b94df23 100644 --- a/src/imports/models/plugins.qmltypes +++ b/src/imports/models/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQml.Models 2.13' +// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQml.Models 2.14' Module { dependencies: [] @@ -441,8 +441,8 @@ Module { Signal { name: "defaultIncludeChanged" } Signal { name: "changed" - Parameter { name: "removed"; type: "QQmlV4Handle" } - Parameter { name: "inserted"; type: "QQmlV4Handle" } + Parameter { name: "removed"; type: "QJSValue" } + Parameter { name: "inserted"; type: "QJSValue" } } Method { name: "insert" @@ -478,7 +478,7 @@ Module { } Method { name: "get" - type: "QQmlV4Handle" + type: "QJSValue" Parameter { name: "index"; type: "int" } } } @@ -496,6 +496,7 @@ Module { exportMetaObjectRevisions: [0] Property { name: "count"; type: "int"; isReadonly: true } Property { name: "dynamicRoles"; type: "bool" } + Property { name: "agent"; revision: 14; type: "QObject"; isReadonly: true; isPointer: true } Method { name: "clear" } Method { name: "remove" @@ -511,13 +512,61 @@ Module { } Method { name: "get" - type: "QQmlV4Handle" + type: "QJSValue" Parameter { name: "index"; type: "int" } } Method { name: "set" Parameter { name: "index"; type: "int" } - Parameter { type: "QQmlV4Handle" } + Parameter { name: "value"; type: "QJSValue" } + } + Method { + name: "setProperty" + Parameter { name: "index"; type: "int" } + Parameter { name: "property"; type: "string" } + Parameter { name: "value"; type: "QVariant" } + } + Method { + name: "move" + Parameter { name: "from"; type: "int" } + Parameter { name: "to"; type: "int" } + Parameter { name: "count"; type: "int" } + } + Method { name: "sync" } + } + Component { + name: "QQmlListModelWorkerAgent" + prototype: "QObject" + Property { name: "count"; type: "int"; isReadonly: true } + Property { name: "engine"; type: "QV4::ExecutionEngine"; isPointer: true } + Signal { + name: "engineChanged" + Parameter { name: "engine"; type: "QV4::ExecutionEngine"; isPointer: true } + } + Method { name: "addref" } + Method { name: "release" } + Method { name: "clear" } + Method { + name: "remove" + Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true } + } + Method { + name: "append" + Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true } + } + Method { + name: "insert" + Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true } + } + Method { + name: "get" + type: "QJSValue" + Parameter { name: "index"; type: "int" } + } + Method { + name: "set" + Parameter { name: "index"; type: "int" } + Parameter { name: "value"; type: "QJSValue" } } Method { name: "setProperty" @@ -592,4 +641,18 @@ Module { prototype: "QObject" Property { name: "index"; type: "int"; isReadonly: true } } + Component { + name: "QQuickPackage" + defaultProperty: "data" + prototype: "QObject" + exports: ["QtQml.Models/Package 2.14"] + exportMetaObjectRevisions: [0] + attachedType: "QQuickPackageAttached" + Property { name: "data"; type: "QObject"; isList: true; isReadonly: true } + } + Component { + name: "QQuickPackageAttached" + prototype: "QObject" + Property { name: "name"; type: "string" } + } } diff --git a/src/imports/particles/plugins.qmltypes b/src/imports/particles/plugins.qmltypes index b6db00e683..0fe5dc808c 100644 --- a/src/imports/particles/plugins.qmltypes +++ b/src/imports/particles/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable QtQuick.Particles 2.13' +// 'qmlplugindump -nonrelocatable QtQuick.Particles 2.14' Module { dependencies: ["QtQuick 2.0"] @@ -165,7 +165,7 @@ Module { Property { name: "acceleration"; type: "QQuickDirection"; isPointer: true } Signal { name: "affectParticles" - Parameter { name: "particles"; type: "QQmlV4Handle" } + Parameter { name: "particles"; type: "QJSValue" } Parameter { name: "dt"; type: "double" } } Signal { @@ -668,7 +668,7 @@ Module { Property { name: "velocityFromMovement"; type: "double" } Signal { name: "emitParticles" - Parameter { name: "particles"; type: "QQmlV4Handle" } + Parameter { name: "particles"; type: "QJSValue" } } Signal { name: "particlesPerSecondChanged" @@ -1084,8 +1084,8 @@ Module { Property { name: "emitWidth"; type: "double" } Signal { name: "emitFollowParticles" - Parameter { name: "particles"; type: "QQmlV4Handle" } - Parameter { name: "followed"; type: "QQmlV4Handle" } + Parameter { name: "particles"; type: "QJSValue" } + Parameter { name: "followed"; type: "QJSValue" } } Signal { name: "particlesPerParticlePerSecondChanged" diff --git a/src/imports/qtqml/dependencies.json b/src/imports/qtqml/dependencies.json new file mode 100644 index 0000000000..0d4f101c7a --- /dev/null +++ b/src/imports/qtqml/dependencies.json @@ -0,0 +1,2 @@ +[ +] diff --git a/src/imports/qtqml/plugins.qmltypes b/src/imports/qtqml/plugins.qmltypes index d548a78dd0..8a9bf3f1f1 100644 --- a/src/imports/qtqml/plugins.qmltypes +++ b/src/imports/qtqml/plugins.qmltypes @@ -4,14 +4,14 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable -noforceqtquick QtQml 2.13' +// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQml 2.14' Module { dependencies: [] Component { name: "QObject" - exports: ["QtQml/QtObject 2.0"] - exportMetaObjectRevisions: [0] + exports: ["QML/QtObject 1.0", "QtQml/QtObject 2.0"] + exportMetaObjectRevisions: [0, 0] Property { name: "objectName"; type: "string" } Signal { name: "objectNameChanged" @@ -27,13 +27,27 @@ Module { Component { name: "QQmlBind" prototype: "QObject" - exports: ["QtQml/Binding 2.0", "QtQml/Binding 2.8"] - exportMetaObjectRevisions: [0, 8] + exports: [ + "QtQml/Binding 2.0", + "QtQml/Binding 2.14", + "QtQml/Binding 2.8" + ] + exportMetaObjectRevisions: [0, 14, 8] + Enum { + name: "RestorationMode" + values: { + "RestoreNone": 0, + "RestoreBinding": 1, + "RestoreValue": 2, + "RestoreBindingOrValue": 3 + } + } Property { name: "target"; type: "QObject"; isPointer: true } Property { name: "property"; type: "string" } Property { name: "value"; type: "QVariant" } Property { name: "when"; type: "bool" } Property { name: "delayed"; revision: 8; type: "bool" } + Property { name: "restoreMode"; revision: 14; type: "RestorationMode" } } Component { name: "QQmlComponent" diff --git a/src/imports/qtquick2/plugins.qmltypes b/src/imports/qtquick2/plugins.qmltypes index f006c874da..8f01e5bb37 100644 --- a/src/imports/qtquick2/plugins.qmltypes +++ b/src/imports/qtquick2/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQuick 2.13' +// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQuick 2.14' Module { dependencies: [] @@ -529,8 +529,8 @@ Module { Signal { name: "defaultIncludeChanged" } Signal { name: "changed" - Parameter { name: "removed"; type: "QQmlV4Handle" } - Parameter { name: "inserted"; type: "QQmlV4Handle" } + Parameter { name: "removed"; type: "QJSValue" } + Parameter { name: "inserted"; type: "QJSValue" } } Method { name: "insert" @@ -566,7 +566,7 @@ Module { } Method { name: "get" - type: "QQmlV4Handle" + type: "QJSValue" Parameter { name: "index"; type: "int" } } } @@ -646,6 +646,7 @@ Module { exportMetaObjectRevisions: [0] Property { name: "count"; type: "int"; isReadonly: true } Property { name: "dynamicRoles"; type: "bool" } + Property { name: "agent"; revision: 14; type: "QObject"; isReadonly: true; isPointer: true } Method { name: "clear" } Method { name: "remove" @@ -661,13 +662,61 @@ Module { } Method { name: "get" - type: "QQmlV4Handle" + type: "QJSValue" Parameter { name: "index"; type: "int" } } Method { name: "set" Parameter { name: "index"; type: "int" } - Parameter { type: "QQmlV4Handle" } + Parameter { name: "value"; type: "QJSValue" } + } + Method { + name: "setProperty" + Parameter { name: "index"; type: "int" } + Parameter { name: "property"; type: "string" } + Parameter { name: "value"; type: "QVariant" } + } + Method { + name: "move" + Parameter { name: "from"; type: "int" } + Parameter { name: "to"; type: "int" } + Parameter { name: "count"; type: "int" } + } + Method { name: "sync" } + } + Component { + name: "QQmlListModelWorkerAgent" + prototype: "QObject" + Property { name: "count"; type: "int"; isReadonly: true } + Property { name: "engine"; type: "QV4::ExecutionEngine"; isPointer: true } + Signal { + name: "engineChanged" + Parameter { name: "engine"; type: "QV4::ExecutionEngine"; isPointer: true } + } + Method { name: "addref" } + Method { name: "release" } + Method { name: "clear" } + Method { + name: "remove" + Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true } + } + Method { + name: "append" + Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true } + } + Method { + name: "insert" + Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true } + } + Method { + name: "get" + type: "QJSValue" + Parameter { name: "index"; type: "int" } + } + Method { + name: "set" + Parameter { name: "index"; type: "int" } + Parameter { name: "value"; type: "QJSValue" } } Method { name: "setProperty" @@ -1300,7 +1349,7 @@ Module { } Property { name: "available"; type: "bool"; isReadonly: true } Property { name: "contextType"; type: "string" } - Property { name: "context"; type: "QQmlV4Handle"; isReadonly: true } + Property { name: "context"; type: "QJSValue"; isReadonly: true } Property { name: "canvasSize"; type: "QSizeF" } Property { name: "tileSize"; type: "QSize" } Property { name: "canvasWindow"; type: "QRectF" } @@ -1480,9 +1529,19 @@ Module { prototype: "QQuickMultiPointHandler" exports: ["QtQuick/DragHandler 2.12"] exportMetaObjectRevisions: [0] + Enum { + name: "SnapMode" + values: { + "NoSnap": 0, + "SnapAuto": 1, + "SnapIfPressedOutsideTarget": 2, + "SnapAlways": 3 + } + } Property { name: "xAxis"; type: "QQuickDragAxis"; isReadonly: true; isPointer: true } Property { name: "yAxis"; type: "QQuickDragAxis"; isReadonly: true; isPointer: true } Property { name: "translation"; type: "QVector2D"; isReadonly: true } + Property { name: "snapMode"; type: "SnapMode" } } Component { name: "QQuickDropArea" @@ -1959,7 +2018,13 @@ Module { "Unknown": 0, "Software": 1, "OpenGL": 2, - "Direct3D12": 3 + "Direct3D12": 3, + "OpenVG": 4, + "OpenGLRhi": 5, + "Direct3D11Rhi": 6, + "VulkanRhi": 7, + "MetalRhi": 8, + "NullRhi": 9 } } Enum { @@ -1967,7 +2032,8 @@ Module { values: { "UnknownShadingLanguage": 0, "GLSL": 1, - "HLSL": 2 + "HLSL": 2, + "RhiShader": 3 } } Enum { @@ -3172,13 +3238,21 @@ Module { name: "QQuickPath" defaultProperty: "pathElements" prototype: "QObject" - exports: ["QtQuick/Path 2.0"] - exportMetaObjectRevisions: [0] + exports: ["QtQuick/Path 2.0", "QtQuick/Path 2.14"] + exportMetaObjectRevisions: [0, 14] Property { name: "pathElements"; type: "QQuickPathElement"; isList: true; isReadonly: true } Property { name: "startX"; type: "double" } Property { name: "startY"; type: "double" } Property { name: "closed"; type: "bool"; isReadonly: true } + Property { name: "scale"; revision: 14; type: "QSizeF" } Signal { name: "changed" } + Signal { name: "scaleChanged"; revision: 14 } + Method { + name: "pointAtPercent" + revision: 14 + type: "QPointF" + Parameter { name: "t"; type: "double" } + } } Component { name: "QQuickPathAngleArc" @@ -3321,6 +3395,14 @@ Module { exports: ["QtQuick/PathMove 2.9"] exportMetaObjectRevisions: [0] } + Component { + name: "QQuickPathMultiline" + prototype: "QQuickCurve" + exports: ["QtQuick/PathMultiline 2.14"] + exportMetaObjectRevisions: [0] + Property { name: "start"; type: "QPointF"; isReadonly: true } + Property { name: "paths"; type: "QVariantList" } + } Component { name: "QQuickPathPercent" prototype: "QQuickPathElement" @@ -3328,6 +3410,14 @@ Module { exportMetaObjectRevisions: [0] Property { name: "value"; type: "double" } } + Component { + name: "QQuickPathPolyline" + prototype: "QQuickCurve" + exports: ["QtQuick/PathPolyline 2.14"] + exportMetaObjectRevisions: [0] + Property { name: "start"; type: "QPointF"; isReadonly: true } + Property { name: "path"; type: "QVariantList" } + } Component { name: "QQuickPathQuad" prototype: "QQuickCurve" @@ -4229,7 +4319,7 @@ Module { exports: ["QtQuick/State 2.0"] exportMetaObjectRevisions: [0] Property { name: "name"; type: "string" } - Property { name: "when"; type: "QQmlBinding"; isPointer: true } + Property { name: "when"; type: "bool" } Property { name: "extend"; type: "string" } Property { name: "changes"; type: "QQuickStateOperation"; isList: true; isReadonly: true } Signal { name: "completed" } @@ -4340,8 +4430,8 @@ Module { name: "QQuickTableView" defaultProperty: "flickableData" prototype: "QQuickFlickable" - exports: ["QtQuick/TableView 2.12"] - exportMetaObjectRevisions: [0] + exports: ["QtQuick/TableView 2.12", "QtQuick/TableView 2.14"] + exportMetaObjectRevisions: [0, 14] attachedType: "QQuickTableViewAttached" Property { name: "rows"; type: "int"; isReadonly: true } Property { name: "columns"; type: "int"; isReadonly: true } @@ -4354,6 +4444,10 @@ Module { Property { name: "reuseItems"; type: "bool" } Property { name: "contentWidth"; type: "double" } Property { name: "contentHeight"; type: "double" } + Property { name: "syncView"; revision: 14; type: "QQuickTableView"; isPointer: true } + Property { name: "syncDirection"; revision: 14; type: "Qt::Orientations" } + Signal { name: "syncViewChanged"; revision: 14 } + Signal { name: "syncDirectionChanged"; revision: 14 } Method { name: "forceLayout" } } Component { @@ -4440,6 +4534,7 @@ Module { values: { "PlainText": 0, "RichText": 1, + "MarkdownText": 3, "AutoText": 2, "StyledText": 4 } @@ -4631,7 +4726,8 @@ Module { values: { "PlainText": 0, "RichText": 1, - "AutoText": 2 + "AutoText": 2, + "MarkdownText": 3 } } Enum { @@ -5271,6 +5367,24 @@ Module { Property { name: "inverted"; type: "bool"; isReadonly: true } Property { name: "accepted"; type: "bool" } } + Component { + name: "QQuickWheelHandler" + prototype: "QQuickSinglePointHandler" + exports: ["QtQuick/WheelHandler 2.14"] + exportMetaObjectRevisions: [0] + Property { name: "orientation"; type: "Qt::Orientation" } + Property { name: "invertible"; type: "bool" } + Property { name: "activeTimeout"; type: "double" } + Property { name: "rotation"; type: "double" } + Property { name: "rotationScale"; type: "double" } + Property { name: "property"; type: "string" } + Property { name: "targetScaleMultiplier"; type: "double" } + Property { name: "targetTransformAroundCursor"; type: "bool" } + Signal { + name: "wheel" + Parameter { name: "event"; type: "QQuickPointerScrollEvent"; isPointer: true } + } + } Component { name: "QQuickWorkerScript" prototype: "QObject" @@ -5279,7 +5393,7 @@ Module { Property { name: "source"; type: "QUrl" } Signal { name: "message" - Parameter { name: "messageObject"; type: "QQmlV4Handle" } + Parameter { name: "messageObject"; type: "QJSValue" } } Method { name: "sendMessage" @@ -5309,9 +5423,32 @@ Module { Parameter { name: "regExp"; type: "QRegExp" } } } + Component { + name: "QRegularExpressionValidator" + prototype: "QValidator" + exports: ["QtQuick/RegularExpressionValidator 2.14"] + exportMetaObjectRevisions: [0] + Property { name: "regularExpression"; type: "QRegularExpression" } + Signal { + name: "regularExpressionChanged" + Parameter { name: "re"; type: "QRegularExpression" } + } + Method { + name: "setRegularExpression" + Parameter { name: "re"; type: "QRegularExpression" } + } + } Component { name: "QValidator" prototype: "QObject" + Enum { + name: "State" + values: { + "Invalid": 0, + "Intermediate": 1, + "Acceptable": 2 + } + } Signal { name: "changed" } } } diff --git a/src/imports/shapes/plugins.qmltypes b/src/imports/shapes/plugins.qmltypes index b78c5a1130..cd779e7149 100644 --- a/src/imports/shapes/plugins.qmltypes +++ b/src/imports/shapes/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable QtQuick.Shapes 1.13' +// 'qmlplugindump -nonrelocatable QtQuick.Shapes 1.14' Module { dependencies: ["QtQuick 2.0"] @@ -89,8 +89,11 @@ Module { name: "QQuickShapePath" defaultProperty: "pathElements" prototype: "QQuickPath" - exports: ["QtQuick.Shapes/ShapePath 1.0"] - exportMetaObjectRevisions: [0] + exports: [ + "QtQuick.Shapes/ShapePath 1.0", + "QtQuick.Shapes/ShapePath 1.14" + ] + exportMetaObjectRevisions: [0, 14] Enum { name: "FillRule" values: { @@ -132,6 +135,7 @@ Module { Property { name: "dashOffset"; type: "double" } Property { name: "dashPattern"; type: "QVector" } Property { name: "fillGradient"; type: "QQuickShapeGradient"; isPointer: true } + Property { name: "scale"; revision: 14; type: "QSizeF" } Signal { name: "shapePathChanged" } } Component { diff --git a/src/imports/statemachine/plugins.qmltypes b/src/imports/statemachine/plugins.qmltypes index f92aeaa080..541b1cc114 100644 --- a/src/imports/statemachine/plugins.qmltypes +++ b/src/imports/statemachine/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQml.StateMachine 1.13' +// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQml.StateMachine 1.14' Module { dependencies: [] diff --git a/src/imports/testlib/plugins.qmltypes b/src/imports/testlib/plugins.qmltypes index 1e081d82ff..6a1371e5f1 100644 --- a/src/imports/testlib/plugins.qmltypes +++ b/src/imports/testlib/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable QtTest 1.13' +// 'qmlplugindump -nonrelocatable QtTest 1.14' Module { dependencies: ["QtQuick 2.0", "QtQuick.Window 2.0"] @@ -343,7 +343,7 @@ Module { Property { name: "dragThreshold"; type: "int"; isReadonly: true } Method { name: "typeName" - type: "QQmlV4Handle" + type: "QJSValue" Parameter { name: "v"; type: "QVariant" } } Method { @@ -354,10 +354,10 @@ Module { } Method { name: "callerFile" - type: "QQmlV4Handle" + type: "QJSValue" Parameter { name: "frameIndex"; type: "int" } } - Method { name: "callerFile"; type: "QQmlV4Handle" } + Method { name: "callerFile"; type: "QJSValue" } Method { name: "callerLine" type: "int" diff --git a/src/imports/wavefrontmesh/plugins.qmltypes b/src/imports/wavefrontmesh/plugins.qmltypes index b9dd9e4c46..4e6a1dca73 100644 --- a/src/imports/wavefrontmesh/plugins.qmltypes +++ b/src/imports/wavefrontmesh/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable Qt.labs.wavefrontmesh 1.13' +// 'qmlplugindump -nonrelocatable Qt.labs.wavefrontmesh 1.14' Module { dependencies: ["QtQuick 2.0"] diff --git a/src/imports/window/plugins.qmltypes b/src/imports/window/plugins.qmltypes index b5786ed5a6..596da2d234 100644 --- a/src/imports/window/plugins.qmltypes +++ b/src/imports/window/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable QtQuick.Window 2.13' +// 'qmlplugindump -nonrelocatable QtQuick.Window 2.14' Module { dependencies: ["QtQuick 2.0"] @@ -140,6 +140,8 @@ Module { Parameter { name: "error"; type: "QQuickWindow::SceneGraphError" } Parameter { name: "message"; type: "string" } } + Signal { name: "beforeRenderPassRecording"; revision: 14 } + Signal { name: "afterRenderPassRecording"; revision: 14 } Method { name: "update" } Method { name: "releaseResources" } } diff --git a/src/imports/workerscript/plugins.qmltypes b/src/imports/workerscript/plugins.qmltypes new file mode 100644 index 0000000000..b1d6107022 --- /dev/null +++ b/src/imports/workerscript/plugins.qmltypes @@ -0,0 +1,26 @@ +import QtQuick.tooling 1.2 + +// This file describes the plugin-supplied types contained in the library. +// It is used for QML tooling purposes only. +// +// This file was auto-generated by: +// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQml.WorkerScript 2.14' + +Module { + dependencies: [] + Component { + name: "QQuickWorkerScript" + prototype: "QObject" + exports: ["QtQml.WorkerScript/WorkerScript 2.0"] + exportMetaObjectRevisions: [0] + Property { name: "source"; type: "QUrl" } + Signal { + name: "message" + Parameter { name: "messageObject"; type: "QJSValue" } + } + Method { + name: "sendMessage" + Parameter { type: "QQmlV4Function"; isPointer: true } + } + } +} -- cgit v1.2.3 From 50ccfaa7ad26e0872ac50b92b346bebbd3002838 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 21 Aug 2019 18:32:49 +0200 Subject: Harmonize meta object revisions and minor versions In order to avoid complexity we want those to match. We can easily "rename" the meta object revisions as those are not public interfaces. Change-Id: I48e063d49758c7bacd9b7816bf5541cf67e07b0d Reviewed-by: Simon Hausmann Reviewed-by: Shawn Rutledge Reviewed-by: Fabian Kosmale --- src/imports/qtqml/plugins.qmltypes | 10 ++-- src/imports/qtquick2/plugins.qmltypes | 78 ++++++++++++++-------------- src/imports/window/plugins.qmltypes | 18 +++---- src/qml/qml/qqmlengine.cpp | 8 +-- src/qml/qml/qqmlloggingcategory_p.h | 2 +- src/qml/types/qqmlconnections_p.h | 4 +- src/quick/items/qquickimage_p.h | 8 +-- src/quick/items/qquickitem.h | 2 +- src/quick/items/qquickitemsmodule.cpp | 26 +++++----- src/quick/items/qquickitemview_p.h | 4 +- src/quick/items/qquicklistview_p.h | 8 +-- src/quick/items/qquickmousearea_p.h | 8 +-- src/quick/items/qquickpincharea_p.h | 2 +- src/quick/items/qquickscreen_p.h | 8 +-- src/quick/items/qquickshadereffect_p.h | 2 +- src/quick/items/qquickshadereffectsource_p.h | 4 +- src/quick/items/qquicktextinput_p.h | 8 +-- src/quick/items/qquickwindowmodule.cpp | 8 +-- src/quick/items/qquickwindowmodule_p.h | 4 +- src/quick/util/qquickpath_p.h | 4 +- src/quick/util/qquickshortcut_p.h | 4 +- src/quick/util/qquickutilmodule.cpp | 2 +- 22 files changed, 111 insertions(+), 111 deletions(-) diff --git a/src/imports/qtqml/plugins.qmltypes b/src/imports/qtqml/plugins.qmltypes index 8a9bf3f1f1..63f5bada9b 100644 --- a/src/imports/qtqml/plugins.qmltypes +++ b/src/imports/qtqml/plugins.qmltypes @@ -108,11 +108,11 @@ Module { name: "QQmlConnections" prototype: "QObject" exports: ["QtQml/Connections 2.0", "QtQml/Connections 2.3"] - exportMetaObjectRevisions: [0, 1] + exportMetaObjectRevisions: [0, 3] Property { name: "target"; type: "QObject"; isPointer: true } - Property { name: "enabled"; revision: 1; type: "bool" } + Property { name: "enabled"; revision: 3; type: "bool" } Property { name: "ignoreUnknownSignals"; type: "bool" } - Signal { name: "enabledChanged"; revision: 1 } + Signal { name: "enabledChanged"; revision: 3 } } Component { name: "QQmlInstanceModel" @@ -213,7 +213,7 @@ Module { name: "QQmlLoggingCategory" prototype: "QObject" exports: ["QtQml/LoggingCategory 2.12", "QtQml/LoggingCategory 2.8"] - exportMetaObjectRevisions: [1, 0] + exportMetaObjectRevisions: [12, 0] Enum { name: "DefaultLogLevel" values: { @@ -225,7 +225,7 @@ Module { } } Property { name: "name"; type: "string" } - Property { name: "defaultLogLevel"; revision: 1; type: "DefaultLogLevel" } + Property { name: "defaultLogLevel"; revision: 12; type: "DefaultLogLevel" } } Component { name: "QQmlTimer" diff --git a/src/imports/qtquick2/plugins.qmltypes b/src/imports/qtquick2/plugins.qmltypes index 8f01e5bb37..c8aae2087d 100644 --- a/src/imports/qtquick2/plugins.qmltypes +++ b/src/imports/qtquick2/plugins.qmltypes @@ -2197,7 +2197,7 @@ Module { "QtQuick/Image 2.3", "QtQuick/Image 2.5" ] - exportMetaObjectRevisions: [0, 1, 2] + exportMetaObjectRevisions: [0, 3, 5] Enum { name: "HAlignment" values: { @@ -2231,8 +2231,8 @@ Module { Property { name: "paintedHeight"; type: "double"; isReadonly: true } Property { name: "horizontalAlignment"; type: "HAlignment" } Property { name: "verticalAlignment"; type: "VAlignment" } - Property { name: "mipmap"; revision: 1; type: "bool" } - Property { name: "autoTransform"; revision: 2; type: "bool" } + Property { name: "mipmap"; revision: 3; type: "bool" } + Property { name: "autoTransform"; revision: 5; type: "bool" } Signal { name: "paintedGeometryChanged" } Signal { name: "horizontalAlignmentChanged" @@ -2244,10 +2244,10 @@ Module { } Signal { name: "mipmapChanged" - revision: 1 + revision: 3 Parameter { type: "bool" } } - Signal { name: "autoTransformChanged"; revision: 2 } + Signal { name: "autoTransformChanged"; revision: 5 } } Component { name: "QQuickImageBase" @@ -2308,7 +2308,7 @@ Module { "QtQuick/Item 2.4", "QtQuick/Item 2.7" ] - exportMetaObjectRevisions: [0, 1, 11, 2, 7] + exportMetaObjectRevisions: [0, 1, 11, 4, 7] Enum { name: "Flags" values: { @@ -2428,14 +2428,14 @@ Module { Method { name: "update" } Method { name: "grabToImage" - revision: 2 + revision: 4 type: "bool" Parameter { name: "callback"; type: "QJSValue" } Parameter { name: "targetSize"; type: "QSize" } } Method { name: "grabToImage" - revision: 2 + revision: 4 type: "bool" Parameter { name: "callback"; type: "QJSValue" } } @@ -2568,7 +2568,7 @@ Module { "QtQuick/ItemView 2.7" ] isCreatable: false - exportMetaObjectRevisions: [1, 13, 2, 7] + exportMetaObjectRevisions: [1, 13, 3, 7] Enum { name: "LayoutDirection" values: { @@ -2612,8 +2612,8 @@ Module { Property { name: "keyNavigationWraps"; type: "bool" } Property { name: "keyNavigationEnabled"; revision: 7; type: "bool" } Property { name: "cacheBuffer"; type: "int" } - Property { name: "displayMarginBeginning"; revision: 2; type: "int" } - Property { name: "displayMarginEnd"; revision: 2; type: "int" } + Property { name: "displayMarginBeginning"; revision: 3; type: "int" } + Property { name: "displayMarginEnd"; revision: 3; type: "int" } Property { name: "layoutDirection"; type: "Qt::LayoutDirection" } Property { name: "effectiveLayoutDirection"; type: "Qt::LayoutDirection"; isReadonly: true } Property { name: "verticalLayoutDirection"; type: "VerticalLayoutDirection" } @@ -2924,7 +2924,7 @@ Module { "QtQuick/ListView 2.4", "QtQuick/ListView 2.7" ] - exportMetaObjectRevisions: [0, 1, 2, 7] + exportMetaObjectRevisions: [0, 1, 4, 7] attachedType: "QQuickListViewAttached" Enum { name: "Orientation" @@ -2965,10 +2965,10 @@ Module { Property { name: "section"; type: "QQuickViewSection"; isReadonly: true; isPointer: true } Property { name: "currentSection"; type: "string"; isReadonly: true } Property { name: "snapMode"; type: "SnapMode" } - Property { name: "headerPositioning"; revision: 2; type: "HeaderPositioning" } - Property { name: "footerPositioning"; revision: 2; type: "FooterPositioning" } - Signal { name: "headerPositioningChanged"; revision: 2 } - Signal { name: "footerPositioningChanged"; revision: 2 } + Property { name: "headerPositioning"; revision: 4; type: "HeaderPositioning" } + Property { name: "footerPositioning"; revision: 4; type: "FooterPositioning" } + Signal { name: "headerPositioningChanged"; revision: 4 } + Signal { name: "footerPositioningChanged"; revision: 4 } Method { name: "incrementCurrentIndex" } Method { name: "decrementCurrentIndex" } } @@ -3018,13 +3018,13 @@ Module { "QtQuick/MouseArea 2.5", "QtQuick/MouseArea 2.9" ] - exportMetaObjectRevisions: [0, 1, 2, 9] + exportMetaObjectRevisions: [0, 4, 5, 9] Property { name: "mouseX"; type: "double"; isReadonly: true } Property { name: "mouseY"; type: "double"; isReadonly: true } Property { name: "containsMouse"; type: "bool"; isReadonly: true } Property { name: "pressed"; type: "bool"; isReadonly: true } Property { name: "enabled"; type: "bool" } - Property { name: "scrollGestureEnabled"; revision: 2; type: "bool" } + Property { name: "scrollGestureEnabled"; revision: 5; type: "bool" } Property { name: "pressedButtons"; type: "Qt::MouseButtons"; isReadonly: true } Property { name: "acceptedButtons"; type: "Qt::MouseButtons" } Property { name: "hoverEnabled"; type: "bool" } @@ -3032,10 +3032,10 @@ Module { Property { name: "preventStealing"; type: "bool" } Property { name: "propagateComposedEvents"; type: "bool" } Property { name: "cursorShape"; type: "Qt::CursorShape" } - Property { name: "containsPress"; revision: 1; type: "bool"; isReadonly: true } + Property { name: "containsPress"; revision: 4; type: "bool"; isReadonly: true } Property { name: "pressAndHoldInterval"; revision: 9; type: "int" } Signal { name: "hoveredChanged" } - Signal { name: "scrollGestureEnabledChanged"; revision: 2 } + Signal { name: "scrollGestureEnabledChanged"; revision: 5 } Signal { name: "positionChanged" Parameter { name: "mouse"; type: "QQuickMouseEvent"; isPointer: true } @@ -3075,7 +3075,7 @@ Module { Signal { name: "entered" } Signal { name: "exited" } Signal { name: "canceled" } - Signal { name: "containsPressChanged"; revision: 1 } + Signal { name: "containsPressChanged"; revision: 4 } Signal { name: "pressAndHoldIntervalChanged"; revision: 9 } } Component { @@ -3324,7 +3324,7 @@ Module { name: "QQuickPathArc" prototype: "QQuickCurve" exports: ["QtQuick/PathArc 2.0", "QtQuick/PathArc 2.9"] - exportMetaObjectRevisions: [0, 2] + exportMetaObjectRevisions: [0, 9] Enum { name: "ArcDirection" values: { @@ -3336,8 +3336,8 @@ Module { Property { name: "radiusY"; type: "double" } Property { name: "useLargeArc"; type: "bool" } Property { name: "direction"; type: "ArcDirection" } - Property { name: "xAxisRotation"; revision: 2; type: "double" } - Signal { name: "xAxisRotationChanged"; revision: 2 } + Property { name: "xAxisRotation"; revision: 9; type: "double" } + Signal { name: "xAxisRotationChanged"; revision: 9 } } Component { name: "QQuickPathAttribute" @@ -3598,7 +3598,7 @@ Module { defaultProperty: "data" prototype: "QQuickItem" exports: ["QtQuick/PinchArea 2.0", "QtQuick/PinchArea 2.5"] - exportMetaObjectRevisions: [0, 1] + exportMetaObjectRevisions: [0, 5] Property { name: "enabled"; type: "bool" } Property { name: "pinch"; type: "QQuickPinch"; isReadonly: true; isPointer: true } Signal { @@ -3615,7 +3615,7 @@ Module { } Signal { name: "smartZoom" - revision: 1 + revision: 5 Parameter { name: "pinch"; type: "QQuickPinchEvent"; isPointer: true } } } @@ -4010,7 +4010,7 @@ Module { defaultProperty: "data" prototype: "QQuickItem" exports: ["QtQuick/ShaderEffect 2.0", "QtQuick/ShaderEffect 2.4"] - exportMetaObjectRevisions: [0, 1] + exportMetaObjectRevisions: [0, 4] Enum { name: "CullMode" values: { @@ -4034,7 +4034,7 @@ Module { Property { name: "cullMode"; type: "CullMode" } Property { name: "log"; type: "string"; isReadonly: true } Property { name: "status"; type: "Status"; isReadonly: true } - Property { name: "supportsAtlasTextures"; revision: 1; type: "bool" } + Property { name: "supportsAtlasTextures"; revision: 4; type: "bool" } } Component { name: "QQuickShaderEffectMesh" @@ -4053,7 +4053,7 @@ Module { "QtQuick/ShaderEffectSource 2.6", "QtQuick/ShaderEffectSource 2.9" ] - exportMetaObjectRevisions: [0, 1, 2] + exportMetaObjectRevisions: [0, 6, 9] Enum { name: "WrapMode" values: { @@ -4088,8 +4088,8 @@ Module { Property { name: "hideSource"; type: "bool" } Property { name: "mipmap"; type: "bool" } Property { name: "recursive"; type: "bool" } - Property { name: "textureMirroring"; revision: 1; type: "TextureMirroring" } - Property { name: "samples"; revision: 2; type: "int" } + Property { name: "textureMirroring"; revision: 6; type: "TextureMirroring" } + Property { name: "samples"; revision: 9; type: "int" } Signal { name: "scheduledUpdateCompleted" } Method { name: "scheduleUpdate" } } @@ -4101,11 +4101,11 @@ Module { "QtQuick/Shortcut 2.6", "QtQuick/Shortcut 2.9" ] - exportMetaObjectRevisions: [0, 1, 9] + exportMetaObjectRevisions: [0, 6, 9] Property { name: "sequence"; type: "QVariant" } Property { name: "sequences"; revision: 9; type: "QVariantList" } - Property { name: "nativeText"; revision: 1; type: "string"; isReadonly: true } - Property { name: "portableText"; revision: 1; type: "string"; isReadonly: true } + Property { name: "nativeText"; revision: 6; type: "string"; isReadonly: true } + Property { name: "portableText"; revision: 6; type: "string"; isReadonly: true } Property { name: "enabled"; type: "bool" } Property { name: "autoRepeat"; type: "bool" } Property { name: "context"; type: "Qt::ShortcutContext" } @@ -4988,7 +4988,7 @@ Module { "QtQuick/TextInput 2.7", "QtQuick/TextInput 2.9" ] - exportMetaObjectRevisions: [0, 2, 3, 6, 7, 9] + exportMetaObjectRevisions: [0, 2, 4, 6, 7, 9] Enum { name: "EchoMode" values: { @@ -5072,7 +5072,7 @@ Module { Property { name: "echoMode"; type: "EchoMode" } Property { name: "activeFocusOnPress"; type: "bool" } Property { name: "passwordCharacter"; type: "string" } - Property { name: "passwordMaskDelay"; revision: 3; type: "int" } + Property { name: "passwordMaskDelay"; revision: 4; type: "int" } Property { name: "displayText"; type: "string"; isReadonly: true } Property { name: "preeditText"; revision: 7; type: "string"; isReadonly: true } Property { name: "autoScroll"; type: "bool" } @@ -5132,7 +5132,7 @@ Module { } Signal { name: "passwordMaskDelayChanged" - revision: 3 + revision: 4 Parameter { name: "delay"; type: "int" } } Signal { name: "preeditTextChanged"; revision: 7 } @@ -5189,7 +5189,7 @@ Module { } Method { name: "ensureVisible" - revision: 3 + revision: 4 Parameter { name: "position"; type: "int" } } Method { name: "clear"; revision: 7 } @@ -5213,7 +5213,7 @@ Module { } Method { name: "inputMethodQuery" - revision: 3 + revision: 4 type: "QVariant" Parameter { name: "query"; type: "Qt::InputMethodQuery" } Parameter { name: "argument"; type: "QVariant" } diff --git a/src/imports/window/plugins.qmltypes b/src/imports/window/plugins.qmltypes index 596da2d234..82b7ce0fc5 100644 --- a/src/imports/window/plugins.qmltypes +++ b/src/imports/window/plugins.qmltypes @@ -26,7 +26,7 @@ Module { prototype: "QObject" exports: ["QtQuick.Window/Screen 2.0", "QtQuick.Window/Screen 2.3"] isCreatable: false - exportMetaObjectRevisions: [0, 1] + exportMetaObjectRevisions: [0, 3] attachedType: "QQuickScreenAttached" } Component { @@ -48,7 +48,7 @@ Module { "QtQuick.Window/ScreenInfo 2.3" ] isCreatable: false - exportMetaObjectRevisions: [10, 2] + exportMetaObjectRevisions: [10, 3] Property { name: "name"; type: "string"; isReadonly: true } Property { name: "manufacturer"; revision: 10; type: "string"; isReadonly: true } Property { name: "model"; revision: 10; type: "string"; isReadonly: true } @@ -62,14 +62,14 @@ Module { Property { name: "devicePixelRatio"; type: "double"; isReadonly: true } Property { name: "primaryOrientation"; type: "Qt::ScreenOrientation"; isReadonly: true } Property { name: "orientation"; type: "Qt::ScreenOrientation"; isReadonly: true } - Property { name: "virtualX"; revision: 1; type: "int"; isReadonly: true } - Property { name: "virtualY"; revision: 1; type: "int"; isReadonly: true } + Property { name: "virtualX"; revision: 3; type: "int"; isReadonly: true } + Property { name: "virtualY"; revision: 3; type: "int"; isReadonly: true } Signal { name: "manufacturerChanged"; revision: 10 } Signal { name: "modelChanged"; revision: 10 } Signal { name: "serialNumberChanged"; revision: 10 } Signal { name: "desktopGeometryChanged" } - Signal { name: "virtualXChanged"; revision: 1 } - Signal { name: "virtualYChanged"; revision: 1 } + Signal { name: "virtualXChanged"; revision: 3 } + Signal { name: "virtualYChanged"; revision: 3 } } Component { name: "QQuickWindow" @@ -166,11 +166,11 @@ Module { "QtQuick.Window/Window 2.2", "QtQuick.Window/Window 2.3" ] - exportMetaObjectRevisions: [0, 13, 1, 2] + exportMetaObjectRevisions: [0, 13, 2, 3] attachedType: "QQuickWindowAttached" Property { name: "visible"; type: "bool" } Property { name: "visibility"; type: "Visibility" } - Property { name: "screen"; revision: 2; type: "QObject"; isPointer: true } + Property { name: "screen"; revision: 3; type: "QObject"; isPointer: true } Signal { name: "visibleChanged" Parameter { name: "arg"; type: "bool" } @@ -179,7 +179,7 @@ Module { name: "visibilityChanged" Parameter { name: "visibility"; type: "QWindow::Visibility" } } - Signal { name: "screenChanged"; revision: 2 } + Signal { name: "screenChanged"; revision: 3 } } Component { name: "QWindow" diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 9c3c9de81e..0fd07ea209 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -210,14 +210,14 @@ void QQmlEnginePrivate::defineModule() // TODO: We won't need Connections to be a custom type anymore once we can drop the // automatic signal handler inference from undeclared properties. qmlRegisterCustomType(uri, 2, 0, "Connections", new QQmlConnectionsParser); - qmlRegisterCustomType(uri, 2, 3, "Connections", new QQmlConnectionsParser); // Only available in QtQml >= 2.3 + qmlRegisterCustomType(uri, 2, 3, "Connections", new QQmlConnectionsParser); // Only available in QtQml >= 2.3 #if QT_CONFIG(qml_animation) qmlRegisterType(uri, 2, 0, "Timer"); #endif qmlRegisterType(uri, 2, 8, "LoggingCategory"); // Only available in >= 2.8 - qmlRegisterType(uri, 2, 12, "LoggingCategory"); // Only available in >= 2.12 + qmlRegisterType(uri, 2, 12, "LoggingCategory"); // Only available in >= 2.12 #if QT_CONFIG(qml_locale) qmlRegisterUncreatableType(uri, 2, 2, "Locale", QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()")); @@ -236,12 +236,12 @@ void QQmlEnginePrivate::registerQuickTypes() qmlRegisterType(uri, 2, 0, "Binding"); qmlRegisterType(uri, 2, 8, "Binding"); qmlRegisterCustomType(uri, 2, 0, "Connections", new QQmlConnectionsParser); - qmlRegisterCustomType(uri, 2, 7, "Connections", new QQmlConnectionsParser); + qmlRegisterCustomType(uri, 2, 7, "Connections", new QQmlConnectionsParser); #if QT_CONFIG(qml_animation) qmlRegisterType(uri, 2, 0,"Timer"); #endif qmlRegisterType(uri, 2, 8, "LoggingCategory"); - qmlRegisterType(uri, 2, 12, "LoggingCategory"); + qmlRegisterType(uri, 2, 12, "LoggingCategory"); #if QT_CONFIG(qml_locale) qmlRegisterUncreatableType(uri, 2, 0, "Locale", QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()")); #endif diff --git a/src/qml/qml/qqmlloggingcategory_p.h b/src/qml/qml/qqmlloggingcategory_p.h index ece06e04b4..ee5d9af2e7 100644 --- a/src/qml/qml/qqmlloggingcategory_p.h +++ b/src/qml/qml/qqmlloggingcategory_p.h @@ -65,7 +65,7 @@ class QQmlLoggingCategory : public QObject, public QQmlParserStatus Q_INTERFACES(QQmlParserStatus) Q_PROPERTY(QString name READ name WRITE setName) - Q_PROPERTY(DefaultLogLevel defaultLogLevel READ defaultLogLevel WRITE setDefaultLogLevel REVISION 1) + Q_PROPERTY(DefaultLogLevel defaultLogLevel READ defaultLogLevel WRITE setDefaultLogLevel REVISION 12) public: enum DefaultLogLevel { diff --git a/src/qml/types/qqmlconnections_p.h b/src/qml/types/qqmlconnections_p.h index 1acc86239f..5d28e8e8be 100644 --- a/src/qml/types/qqmlconnections_p.h +++ b/src/qml/types/qqmlconnections_p.h @@ -69,7 +69,7 @@ class Q_AUTOTEST_EXPORT QQmlConnections : public QObject, public QQmlParserStatu Q_INTERFACES(QQmlParserStatus) Q_PROPERTY(QObject *target READ target WRITE setTarget NOTIFY targetChanged) - Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged REVISION 1) + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged REVISION 3) Q_PROPERTY(bool ignoreUnknownSignals READ ignoreUnknownSignals WRITE setIgnoreUnknownSignals) public: @@ -87,7 +87,7 @@ public: Q_SIGNALS: void targetChanged(); - Q_REVISION(1) void enabledChanged(); + Q_REVISION(3) void enabledChanged(); private: void connectSignals(); diff --git a/src/quick/items/qquickimage_p.h b/src/quick/items/qquickimage_p.h index 7fb4413900..257cde5313 100644 --- a/src/quick/items/qquickimage_p.h +++ b/src/quick/items/qquickimage_p.h @@ -66,8 +66,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickImage : public QQuickImageBase Q_PROPERTY(qreal paintedHeight READ paintedHeight NOTIFY paintedGeometryChanged) Q_PROPERTY(HAlignment horizontalAlignment READ horizontalAlignment WRITE setHorizontalAlignment NOTIFY horizontalAlignmentChanged) Q_PROPERTY(VAlignment verticalAlignment READ verticalAlignment WRITE setVerticalAlignment NOTIFY verticalAlignmentChanged) - Q_PROPERTY(bool mipmap READ mipmap WRITE setMipmap NOTIFY mipmapChanged REVISION 1) - Q_PROPERTY(bool autoTransform READ autoTransform WRITE setAutoTransform NOTIFY autoTransformChanged REVISION 2) + Q_PROPERTY(bool mipmap READ mipmap WRITE setMipmap NOTIFY mipmapChanged REVISION 3) + Q_PROPERTY(bool autoTransform READ autoTransform WRITE setAutoTransform NOTIFY autoTransformChanged REVISION 5) public: QQuickImage(QQuickItem *parent=nullptr); @@ -112,8 +112,8 @@ Q_SIGNALS: void paintedGeometryChanged(); void horizontalAlignmentChanged(HAlignment alignment); void verticalAlignmentChanged(VAlignment alignment); - Q_REVISION(1) void mipmapChanged(bool); - Q_REVISION(2) void autoTransformChanged(); + Q_REVISION(3) void mipmapChanged(bool); + Q_REVISION(5) void autoTransformChanged(); private Q_SLOTS: void invalidateSceneGraph(); diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h index ad9bab2a90..394a5adb8c 100644 --- a/src/quick/items/qquickitem.h +++ b/src/quick/items/qquickitem.h @@ -318,7 +318,7 @@ public: void setKeepTouchGrab(bool); // implemented in qquickitemgrabresult.cpp - Q_REVISION(2) Q_INVOKABLE bool grabToImage(const QJSValue &callback, const QSize &targetSize = QSize()); + Q_REVISION(4) Q_INVOKABLE bool grabToImage(const QJSValue &callback, const QSize &targetSize = QSize()); QSharedPointer grabToImage(const QSize &targetSize = QSize()); Q_INVOKABLE virtual bool contains(const QPointF &point) const; diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index 6ce079a0dc..70a8b08822 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -246,7 +246,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType(uri,2,1,"TextEdit"); qmlRegisterType(uri,major,minor,"TextInput"); qmlRegisterType(uri,2,2,"TextInput"); - qmlRegisterType(uri,2,4,"TextInput"); + qmlRegisterType(uri,2,4,"TextInput"); qmlRegisterAnonymousType(uri, major); #if QT_CONFIG(quick_shadereffect) qmlRegisterAnonymousType(uri, major); @@ -334,7 +334,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) const char *itemViewName = "ItemView"; const QString itemViewMessage = QQuickItemView::tr("ItemView is an abstract base class"); qmlRegisterUncreatableType(uri, 2, 1, itemViewName, itemViewMessage); - qmlRegisterUncreatableType(uri, 2, 3, itemViewName, itemViewMessage); + qmlRegisterUncreatableType(uri, 2, 3, itemViewName, itemViewMessage); #endif #if QT_CONFIG(quick_listview) qmlRegisterType(uri, 2, 1, "ListView"); @@ -349,23 +349,23 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType(uri, 2, 3, "Text"); qmlRegisterType(uri, 2, 3, "TextEdit"); - qmlRegisterType(uri, 2, 3,"Image"); + qmlRegisterType(uri, 2, 3,"Image"); - qmlRegisterType(uri, 2, 4, "Item"); + qmlRegisterType(uri, 2, 4, "Item"); #if QT_CONFIG(quick_listview) - qmlRegisterType(uri, 2, 4, "ListView"); + qmlRegisterType(uri, 2, 4, "ListView"); #endif - qmlRegisterType(uri, 2, 4, "MouseArea"); + qmlRegisterType(uri, 2, 4, "MouseArea"); #if QT_CONFIG(quick_shadereffect) - qmlRegisterType(uri, 2, 4, "ShaderEffect"); + qmlRegisterType(uri, 2, 4, "ShaderEffect"); #endif #if QT_CONFIG(opengl) qmlRegisterUncreatableType(uri, 2, 4,"OpenGLInfo", QQuickOpenGLInfo::tr("OpenGLInfo is only available via attached properties")); #endif - qmlRegisterType(uri, 2, 5,"PinchArea"); - qmlRegisterType(uri, 2, 5,"Image"); - qmlRegisterType(uri, 2, 5, "MouseArea"); + qmlRegisterType(uri, 2, 5,"PinchArea"); + qmlRegisterType(uri, 2, 5,"Image"); + qmlRegisterType(uri, 2, 5, "MouseArea"); qmlRegisterType(uri, 2, 6, "Text"); qmlRegisterType(uri, 2, 6, "TextEdit"); @@ -381,7 +381,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterUncreatableType(uri, 2, 6, "EnterKey", QQuickEnterKeyAttached::tr("EnterKey is only available via attached properties")); #if QT_CONFIG(quick_shadereffect) - qmlRegisterType(uri, 2, 6, "ShaderEffectSource"); + qmlRegisterType(uri, 2, 6, "ShaderEffectSource"); #endif qmlRegisterType(uri, 2, 7, "Item"); @@ -411,7 +411,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType(uri, 2, 9, "MouseArea"); #if QT_CONFIG(quick_path) - qmlRegisterType(uri, 2, 9, "PathArc"); + qmlRegisterType(uri, 2, 9, "PathArc"); qmlRegisterType(uri, 2, 9, "PathMove"); #endif @@ -426,7 +426,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) #endif #if QT_CONFIG(quick_shadereffect) - qmlRegisterType(uri, 2, 9, "ShaderEffectSource"); + qmlRegisterType(uri, 2, 9, "ShaderEffectSource"); #endif qmlRegisterType(uri, 2, 10, "Flickable"); diff --git a/src/quick/items/qquickitemview_p.h b/src/quick/items/qquickitemview_p.h index 0a0da587b4..66e09f9ed1 100644 --- a/src/quick/items/qquickitemview_p.h +++ b/src/quick/items/qquickitemview_p.h @@ -81,8 +81,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickItemView : public QQuickFlickable Q_PROPERTY(bool keyNavigationWraps READ isWrapEnabled WRITE setWrapEnabled NOTIFY keyNavigationWrapsChanged) Q_PROPERTY(bool keyNavigationEnabled READ isKeyNavigationEnabled WRITE setKeyNavigationEnabled NOTIFY keyNavigationEnabledChanged REVISION 7) Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged) - Q_PROPERTY(int displayMarginBeginning READ displayMarginBeginning WRITE setDisplayMarginBeginning NOTIFY displayMarginBeginningChanged REVISION 2) - Q_PROPERTY(int displayMarginEnd READ displayMarginEnd WRITE setDisplayMarginEnd NOTIFY displayMarginEndChanged REVISION 2) + Q_PROPERTY(int displayMarginBeginning READ displayMarginBeginning WRITE setDisplayMarginBeginning NOTIFY displayMarginBeginningChanged REVISION 3) + Q_PROPERTY(int displayMarginEnd READ displayMarginEnd WRITE setDisplayMarginEnd NOTIFY displayMarginEndChanged REVISION 3) Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged) Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged) diff --git a/src/quick/items/qquicklistview_p.h b/src/quick/items/qquicklistview_p.h index 9a9b325b1e..f2bab9e018 100644 --- a/src/quick/items/qquicklistview_p.h +++ b/src/quick/items/qquicklistview_p.h @@ -126,8 +126,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickListView : public QQuickItemView Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged) - Q_PROPERTY(HeaderPositioning headerPositioning READ headerPositioning WRITE setHeaderPositioning NOTIFY headerPositioningChanged REVISION 2) - Q_PROPERTY(FooterPositioning footerPositioning READ footerPositioning WRITE setFooterPositioning NOTIFY footerPositioningChanged REVISION 2) + Q_PROPERTY(HeaderPositioning headerPositioning READ headerPositioning WRITE setHeaderPositioning NOTIFY headerPositioningChanged REVISION 4) + Q_PROPERTY(FooterPositioning footerPositioning READ footerPositioning WRITE setFooterPositioning NOTIFY footerPositioningChanged REVISION 4) Q_CLASSINFO("DefaultProperty", "data") @@ -188,8 +188,8 @@ Q_SIGNALS: void highlightResizeVelocityChanged(); void highlightResizeDurationChanged(); void snapModeChanged(); - Q_REVISION(2) void headerPositioningChanged(); - Q_REVISION(2) void footerPositioningChanged(); + Q_REVISION(4) void headerPositioningChanged(); + Q_REVISION(4) void footerPositioningChanged(); protected: void viewportMoved(Qt::Orientations orient) override; diff --git a/src/quick/items/qquickmousearea_p.h b/src/quick/items/qquickmousearea_p.h index 76e5c98b35..0e01fa7915 100644 --- a/src/quick/items/qquickmousearea_p.h +++ b/src/quick/items/qquickmousearea_p.h @@ -71,7 +71,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickMouseArea : public QQuickItem Q_PROPERTY(bool containsMouse READ hovered NOTIFY hoveredChanged) Q_PROPERTY(bool pressed READ pressed NOTIFY pressedChanged) Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged) - Q_PROPERTY(bool scrollGestureEnabled READ isScrollGestureEnabled WRITE setScrollGestureEnabled NOTIFY scrollGestureEnabledChanged REVISION 2) + Q_PROPERTY(bool scrollGestureEnabled READ isScrollGestureEnabled WRITE setScrollGestureEnabled NOTIFY scrollGestureEnabledChanged REVISION 5) Q_PROPERTY(Qt::MouseButtons pressedButtons READ pressedButtons NOTIFY pressedButtonsChanged) Q_PROPERTY(Qt::MouseButtons acceptedButtons READ acceptedButtons WRITE setAcceptedButtons NOTIFY acceptedButtonsChanged) Q_PROPERTY(bool hoverEnabled READ hoverEnabled WRITE setHoverEnabled NOTIFY hoverEnabledChanged) @@ -83,7 +83,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickMouseArea : public QQuickItem #if QT_CONFIG(cursor) Q_PROPERTY(Qt::CursorShape cursorShape READ cursorShape WRITE setCursorShape RESET unsetCursor NOTIFY cursorShapeChanged) #endif - Q_PROPERTY(bool containsPress READ containsPress NOTIFY containsPressChanged REVISION 1) + Q_PROPERTY(bool containsPress READ containsPress NOTIFY containsPressChanged REVISION 4) Q_PROPERTY(int pressAndHoldInterval READ pressAndHoldInterval WRITE setPressAndHoldInterval NOTIFY pressAndHoldIntervalChanged RESET resetPressAndHoldInterval REVISION 9) public: @@ -134,7 +134,7 @@ Q_SIGNALS: void hoveredChanged(); void pressedChanged(); void enabledChanged(); - Q_REVISION(2) void scrollGestureEnabledChanged(); + Q_REVISION(5) void scrollGestureEnabledChanged(); void pressedButtonsChanged(); void acceptedButtonsChanged(); void hoverEnabledChanged(); @@ -156,7 +156,7 @@ Q_SIGNALS: void entered(); void exited(); void canceled(); - Q_REVISION(1) void containsPressChanged(); + Q_REVISION(4) void containsPressChanged(); Q_REVISION(9) void pressAndHoldIntervalChanged(); protected: diff --git a/src/quick/items/qquickpincharea_p.h b/src/quick/items/qquickpincharea_p.h index 579a3ce27c..cf21555823 100644 --- a/src/quick/items/qquickpincharea_p.h +++ b/src/quick/items/qquickpincharea_p.h @@ -283,7 +283,7 @@ Q_SIGNALS: void pinchStarted(QQuickPinchEvent *pinch); void pinchUpdated(QQuickPinchEvent *pinch); void pinchFinished(QQuickPinchEvent *pinch); - Q_REVISION(1) void smartZoom(QQuickPinchEvent *pinch); + Q_REVISION(5) void smartZoom(QQuickPinchEvent *pinch); protected: bool childMouseEventFilter(QQuickItem *i, QEvent *e) override; diff --git a/src/quick/items/qquickscreen_p.h b/src/quick/items/qquickscreen_p.h index e9db07d14c..10e524e4a0 100644 --- a/src/quick/items/qquickscreen_p.h +++ b/src/quick/items/qquickscreen_p.h @@ -83,8 +83,8 @@ class Q_AUTOTEST_EXPORT QQuickScreenInfo : public QObject // TODO Qt 6 Remove this orientation -> incomplete device orientation -> better use OrientationSensor Q_PROPERTY(Qt::ScreenOrientation orientation READ orientation NOTIFY orientationChanged) - Q_PROPERTY(int virtualX READ virtualX NOTIFY virtualXChanged REVISION 1) - Q_PROPERTY(int virtualY READ virtualY NOTIFY virtualYChanged REVISION 1) + Q_PROPERTY(int virtualX READ virtualX NOTIFY virtualXChanged REVISION 3) + Q_PROPERTY(int virtualY READ virtualY NOTIFY virtualYChanged REVISION 3) public: QQuickScreenInfo(QObject *parent = nullptr, QScreen *wrappedScreen = nullptr); @@ -121,8 +121,8 @@ Q_SIGNALS: void devicePixelRatioChanged(); void primaryOrientationChanged(); void orientationChanged(); - Q_REVISION(1) void virtualXChanged(); - Q_REVISION(1) void virtualYChanged(); + Q_REVISION(3) void virtualXChanged(); + Q_REVISION(3) void virtualYChanged(); protected: QPointer m_screen; diff --git a/src/quick/items/qquickshadereffect_p.h b/src/quick/items/qquickshadereffect_p.h index c5bddc40d2..6e2f35882b 100644 --- a/src/quick/items/qquickshadereffect_p.h +++ b/src/quick/items/qquickshadereffect_p.h @@ -74,7 +74,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffect : public QQuickItem Q_PROPERTY(CullMode cullMode READ cullMode WRITE setCullMode NOTIFY cullModeChanged) Q_PROPERTY(QString log READ log NOTIFY logChanged) Q_PROPERTY(Status status READ status NOTIFY statusChanged) - Q_PROPERTY(bool supportsAtlasTextures READ supportsAtlasTextures WRITE setSupportsAtlasTextures NOTIFY supportsAtlasTexturesChanged REVISION 1) + Q_PROPERTY(bool supportsAtlasTextures READ supportsAtlasTextures WRITE setSupportsAtlasTextures NOTIFY supportsAtlasTexturesChanged REVISION 4) public: enum CullMode { diff --git a/src/quick/items/qquickshadereffectsource_p.h b/src/quick/items/qquickshadereffectsource_p.h index d5bb33902a..d612d1179f 100644 --- a/src/quick/items/qquickshadereffectsource_p.h +++ b/src/quick/items/qquickshadereffectsource_p.h @@ -87,8 +87,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffectSource : public QQuickItem, publi Q_PROPERTY(bool hideSource READ hideSource WRITE setHideSource NOTIFY hideSourceChanged) Q_PROPERTY(bool mipmap READ mipmap WRITE setMipmap NOTIFY mipmapChanged) Q_PROPERTY(bool recursive READ recursive WRITE setRecursive NOTIFY recursiveChanged) - Q_PROPERTY(TextureMirroring textureMirroring READ textureMirroring WRITE setTextureMirroring NOTIFY textureMirroringChanged REVISION 1) - Q_PROPERTY(int samples READ samples WRITE setSamples NOTIFY samplesChanged REVISION 2) + Q_PROPERTY(TextureMirroring textureMirroring READ textureMirroring WRITE setTextureMirroring NOTIFY textureMirroringChanged REVISION 6) + Q_PROPERTY(int samples READ samples WRITE setSamples NOTIFY samplesChanged REVISION 9) public: enum WrapMode { diff --git a/src/quick/items/qquicktextinput_p.h b/src/quick/items/qquicktextinput_p.h index c46a2f8128..92f3aa62ce 100644 --- a/src/quick/items/qquicktextinput_p.h +++ b/src/quick/items/qquicktextinput_p.h @@ -93,7 +93,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextInput : public QQuickImplicitSizeItem Q_PROPERTY(EchoMode echoMode READ echoMode WRITE setEchoMode NOTIFY echoModeChanged) Q_PROPERTY(bool activeFocusOnPress READ focusOnPress WRITE setFocusOnPress NOTIFY activeFocusOnPressChanged) Q_PROPERTY(QString passwordCharacter READ passwordCharacter WRITE setPasswordCharacter NOTIFY passwordCharacterChanged) - Q_PROPERTY(int passwordMaskDelay READ passwordMaskDelay WRITE setPasswordMaskDelay RESET resetPasswordMaskDelay NOTIFY passwordMaskDelayChanged REVISION 3) + Q_PROPERTY(int passwordMaskDelay READ passwordMaskDelay WRITE setPasswordMaskDelay RESET resetPasswordMaskDelay NOTIFY passwordMaskDelayChanged REVISION 4) Q_PROPERTY(QString displayText READ displayText NOTIFY displayTextChanged) Q_PROPERTY(QString preeditText READ preeditText NOTIFY preeditTextChanged REVISION 7) Q_PROPERTY(bool autoScroll READ autoScroll WRITE setAutoScroll NOTIFY autoScrollChanged) @@ -268,7 +268,7 @@ public: #if QT_CONFIG(im) QVariant inputMethodQuery(Qt::InputMethodQuery property) const override; - Q_REVISION(3) Q_INVOKABLE QVariant inputMethodQuery(Qt::InputMethodQuery query, QVariant argument) const; + Q_REVISION(4) Q_INVOKABLE QVariant inputMethodQuery(Qt::InputMethodQuery query, QVariant argument) const; #endif QRectF boundingRect() const override; @@ -336,7 +336,7 @@ Q_SIGNALS: void inputMaskChanged(const QString &inputMask); void echoModeChanged(QQuickTextInput::EchoMode echoMode); void passwordCharacterChanged(); - Q_REVISION(3) void passwordMaskDelayChanged(int delay); + Q_REVISION(4) void passwordMaskDelayChanged(int delay); void displayTextChanged(); Q_REVISION(7) void preeditTextChanged(); void activeFocusOnPressChanged(bool activeFocusOnPress); @@ -399,7 +399,7 @@ public Q_SLOTS: void redo(); void insert(int position, const QString &text); void remove(int start, int end); - Q_REVISION(3) void ensureVisible(int position); + Q_REVISION(4) void ensureVisible(int position); Q_REVISION(7) void clear(); private Q_SLOTS: diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp index 7b3874dbfe..4b2b8f498d 100644 --- a/src/quick/items/qquickwindowmodule.cpp +++ b/src/quick/items/qquickwindowmodule.cpp @@ -205,11 +205,11 @@ void QQuickWindowModule::defineModule() qmlRegisterRevision(uri, 2, 1);//Type moved to a subclass, but also has new members qmlRegisterRevision(uri, 2, 2); qmlRegisterType(uri, 2, 1, "Window"); - qmlRegisterType(uri, 2, 2, "Window"); - qmlRegisterType(uri, 2, 3, "Window"); + qmlRegisterType(uri, 2, 2, "Window"); + qmlRegisterType(uri, 2, 3, "Window"); qmlRegisterUncreatableType(uri, 2, 0, "Screen", QStringLiteral("Screen can only be used via the attached property.")); - qmlRegisterUncreatableType(uri, 2, 3, "Screen", QStringLiteral("Screen can only be used via the attached property.")); - qmlRegisterUncreatableType(uri, 2, 3, "ScreenInfo", QStringLiteral("ScreenInfo can only be used via the attached property.")); + qmlRegisterUncreatableType(uri, 2, 3, "Screen", QStringLiteral("Screen can only be used via the attached property.")); + qmlRegisterUncreatableType(uri, 2, 3, "ScreenInfo", QStringLiteral("ScreenInfo can only be used via the attached property.")); qmlRegisterUncreatableType(uri, 2, 10, "ScreenInfo", QStringLiteral("ScreenInfo can only be used via the attached property.")); qmlRegisterRevision(uri, 2, 13); qmlRegisterRevision(uri, 2, 13); diff --git a/src/quick/items/qquickwindowmodule_p.h b/src/quick/items/qquickwindowmodule_p.h index e7033e9b8d..1dcf1a1021 100644 --- a/src/quick/items/qquickwindowmodule_p.h +++ b/src/quick/items/qquickwindowmodule_p.h @@ -67,7 +67,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickWindowQmlImpl : public QQuickWindow, public Q Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged) Q_PROPERTY(Visibility visibility READ visibility WRITE setVisibility NOTIFY visibilityChanged) - Q_PROPERTY(QObject *screen READ screen WRITE setScreen NOTIFY screenChanged REVISION 2) + Q_PROPERTY(QObject *screen READ screen WRITE setScreen NOTIFY screenChanged REVISION 3) public: QQuickWindowQmlImpl(QWindow *parent = nullptr); @@ -83,7 +83,7 @@ public: Q_SIGNALS: void visibleChanged(bool arg); void visibilityChanged(QWindow::Visibility visibility); - Q_REVISION(2) void screenChanged(); + Q_REVISION(3) void screenChanged(); protected: void classBegin() override; diff --git a/src/quick/util/qquickpath_p.h b/src/quick/util/qquickpath_p.h index aa3425ff6c..92607a6c1e 100644 --- a/src/quick/util/qquickpath_p.h +++ b/src/quick/util/qquickpath_p.h @@ -290,7 +290,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPathArc : public QQuickCurve Q_PROPERTY(qreal radiusY READ radiusY WRITE setRadiusY NOTIFY radiusYChanged) Q_PROPERTY(bool useLargeArc READ useLargeArc WRITE setUseLargeArc NOTIFY useLargeArcChanged) Q_PROPERTY(ArcDirection direction READ direction WRITE setDirection NOTIFY directionChanged) - Q_PROPERTY(qreal xAxisRotation READ xAxisRotation WRITE setXAxisRotation NOTIFY xAxisRotationChanged REVISION 2) + Q_PROPERTY(qreal xAxisRotation READ xAxisRotation WRITE setXAxisRotation NOTIFY xAxisRotationChanged REVISION 9) public: QQuickPathArc(QObject *parent=nullptr) @@ -321,7 +321,7 @@ Q_SIGNALS: void radiusYChanged(); void useLargeArcChanged(); void directionChanged(); - Q_REVISION(2) void xAxisRotationChanged(); + Q_REVISION(9) void xAxisRotationChanged(); private: qreal _radiusX = 0; diff --git a/src/quick/util/qquickshortcut_p.h b/src/quick/util/qquickshortcut_p.h index c5d5501cb7..712cca7696 100644 --- a/src/quick/util/qquickshortcut_p.h +++ b/src/quick/util/qquickshortcut_p.h @@ -67,8 +67,8 @@ class QQuickShortcut : public QObject, public QQmlParserStatus Q_INTERFACES(QQmlParserStatus) Q_PROPERTY(QVariant sequence READ sequence WRITE setSequence NOTIFY sequenceChanged FINAL) Q_PROPERTY(QVariantList sequences READ sequences WRITE setSequences NOTIFY sequencesChanged FINAL REVISION 9) - Q_PROPERTY(QString nativeText READ nativeText NOTIFY sequenceChanged FINAL REVISION 1) - Q_PROPERTY(QString portableText READ portableText NOTIFY sequenceChanged FINAL REVISION 1) + Q_PROPERTY(QString nativeText READ nativeText NOTIFY sequenceChanged FINAL REVISION 6) + Q_PROPERTY(QString portableText READ portableText NOTIFY sequenceChanged FINAL REVISION 6) Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged FINAL) Q_PROPERTY(bool autoRepeat READ autoRepeat WRITE setAutoRepeat NOTIFY autoRepeatChanged FINAL) Q_PROPERTY(Qt::ShortcutContext context READ context WRITE setContext NOTIFY contextChanged FINAL) diff --git a/src/quick/util/qquickutilmodule.cpp b/src/quick/util/qquickutilmodule.cpp index 7c8134ba6f..93b6599506 100644 --- a/src/quick/util/qquickutilmodule.cpp +++ b/src/quick/util/qquickutilmodule.cpp @@ -131,7 +131,7 @@ void QQuickUtilModule::defineModule() #if QT_CONFIG(shortcut) qmlRegisterType("QtQuick", 2, 5, "Shortcut"); - qmlRegisterType("QtQuick", 2, 6, "Shortcut"); + qmlRegisterType("QtQuick", 2, 6, "Shortcut"); qmlRegisterType("QtQuick", 2, 9, "Shortcut"); #endif -- cgit v1.2.3 From 2ca41fb75721472bab1f9a4f4f9b2428fac7d60d Mon Sep 17 00:00:00 2001 From: Kari Oikarinen Date: Tue, 27 Aug 2019 09:10:51 +0300 Subject: Bump version Change-Id: I454b46a5dbab5ac68c488aa2a25ca244e36277db --- .qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qmake.conf b/.qmake.conf index 076c5b7874..e6642580b9 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -4,4 +4,4 @@ CONFIG += warning_clean DEFINES += QT_NO_LINKED_LIST DEFINES += QT_NO_JAVA_STYLE_ITERATORS -MODULE_VERSION = 5.14.0 +MODULE_VERSION = 5.15.0 -- cgit v1.2.3 From cad232b6536351c68bd11531fa61deaac3226a2f Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Wed, 14 Aug 2019 17:51:06 +0300 Subject: Android multiarch support Change-Id: Ifa70d6cb36be385280364cca9dd4e31b43aa9a18 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/qml/qml/qml.pri | 2 ++ src/qml/qml/qqmlimport.cpp | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri index 08591b5237..2e9c6f3de6 100644 --- a/src/qml/qml/qml.pri +++ b/src/qml/qml/qml.pri @@ -186,5 +186,7 @@ qtConfig(qml-network) { $$PWD/qqmltypeloadernetworkreplyproxy.cpp } +android: DEFINES += LIBS_SUFFIX='\\"_$${QT_ARCH}.so\\"' + include(ftw/ftw.pri) include(v8/v8.pri) diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 7c9c0da01a..31a7004407 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -1852,9 +1852,15 @@ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader, QLatin1String(".so"), QLatin1String(".bundle") }; -# else // Unix +#else // Unix static const QString prefix = QLatin1String("lib"); - static const QStringList suffixes = { QLatin1String(".so") }; + static const QStringList suffixes = { +# if defined(Q_OS_ANDROID) + QStringLiteral(LIBS_SUFFIX), +# endif + QLatin1String(".so") + + }; #endif return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName, suffixes, prefix); -- cgit v1.2.3 From 68b91e7ba42de7774f532b791d989394e6b0fac7 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 21 Aug 2019 17:45:41 +0200 Subject: QQuickDragHandler: Add revision to snapMode This property was added in Qt 5.14. Change-Id: I48ebc614490e67440419965983126740c4443d0e Reviewed-by: Simon Hausmann --- src/quick/handlers/qquickdraghandler_p.h | 4 ++-- src/quick/items/qquickitemsmodule.cpp | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/quick/handlers/qquickdraghandler_p.h b/src/quick/handlers/qquickdraghandler_p.h index 18c1fd841d..e8f47163ed 100644 --- a/src/quick/handlers/qquickdraghandler_p.h +++ b/src/quick/handlers/qquickdraghandler_p.h @@ -62,7 +62,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickDragHandler : public QQuickMultiPointHandler Q_PROPERTY(QQuickDragAxis * xAxis READ xAxis CONSTANT) Q_PROPERTY(QQuickDragAxis * yAxis READ yAxis CONSTANT) Q_PROPERTY(QVector2D translation READ translation NOTIFY translationChanged) - Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged) + Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged REVISION 14) public: enum SnapMode { @@ -89,7 +89,7 @@ public: Q_SIGNALS: void translationChanged(); - void snapModeChanged(); + Q_REVISION(14) void snapModeChanged(); protected: void onActiveChanged() override; diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index 70a8b08822..3927a440e8 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -494,6 +494,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterUncreatableType(uri, 2, 14, "ImageBase", QQuickPointerHandler::tr("ImageBase is an abstract base class")); qmlRegisterType(uri, 2, 14, "Image"); + qmlRegisterType(uri, 2, 14, "DragHandler"); } static void initResources() -- cgit v1.2.3 From a16e802b3d11781a1509e61da43978893989d7a2 Mon Sep 17 00:00:00 2001 From: Alexandru Croitor Date: Wed, 14 Aug 2019 17:28:03 +0200 Subject: CMake: Document newly introduced QT5_IMPORT_QML_PLUGINS function Task-number: QTBUG-38913 Change-Id: I25ada92de8c7d7186c9b083b8a8ccc4427945b28 Reviewed-by: Kavindra Palaraja Reviewed-by: Kai Koehne --- src/quick/doc/snippets/cmake-macros/examples.cmake | 6 +++ src/quick/doc/src/cmake-macros.qdoc | 56 ++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 src/quick/doc/snippets/cmake-macros/examples.cmake create mode 100644 src/quick/doc/src/cmake-macros.qdoc diff --git a/src/quick/doc/snippets/cmake-macros/examples.cmake b/src/quick/doc/snippets/cmake-macros/examples.cmake new file mode 100644 index 0000000000..8ca6180f9b --- /dev/null +++ b/src/quick/doc/snippets/cmake-macros/examples.cmake @@ -0,0 +1,6 @@ +#! [qt5_import_qml_plugins] +find_package(Qt5 COMPONENTS Quick QmlImportScanner) +add_executable(myapp main.cpp) +target_link_libraries(myapp Qt5::Quick) +qt5_import_qml_plugins(myapp) +#! [qt5_import_plugins] diff --git a/src/quick/doc/src/cmake-macros.qdoc b/src/quick/doc/src/cmake-macros.qdoc new file mode 100644 index 0000000000..b643a9e4e4 --- /dev/null +++ b/src/quick/doc/src/cmake-macros.qdoc @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! +\page qtqml-cmake-qt5-import-qml-plugins.html +\ingroup cmake-macros-qtqml + +\title qt5_import_qml_plugins + +\brief Scans \c{.qml} files and imports required QML static plugins + +\section1 Overview + +\badcode +find_package(Qt5QmlImportScanner REQUIRED) +qt5_import_qml_plugins() +\endcode + +\section1 Description + +Runs \c{qmlimportscanner} at configure time to find the static QML plugins +used and links them to the given target. + +\note When used with a non-static Qt build, this function does nothing. + +This CMake command was introduced in Qt 5.14. + +\section1 Example + +\snippet cmake-macros/examples.cmake qt5_import_qml_plugins + +*/ -- cgit v1.2.3 From cda5721e0efbce4b35ba1692c70f8e90b0fd6726 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Wed, 28 Aug 2019 16:19:58 +0200 Subject: Set point size in visualization vertex shader ...in order to avoid a validation layer warning with Vulkan when visualizing overdraw on a scene that includes drawing points (like some types of particles). Change-Id: Ia0a40f850ce5f7a0374c7b8779d5342f191c6973 Reviewed-by: Andy Nichols --- src/quick/scenegraph/shaders_ng/visualization.vert | 4 +++- .../scenegraph/shaders_ng/visualization.vert.qsb | Bin 2030 -> 2099 bytes 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/quick/scenegraph/shaders_ng/visualization.vert b/src/quick/scenegraph/shaders_ng/visualization.vert index c29492417a..e2447948c2 100644 --- a/src/quick/scenegraph/shaders_ng/visualization.vert +++ b/src/quick/scenegraph/shaders_ng/visualization.vert @@ -11,7 +11,7 @@ layout(std140, binding = 0) uniform buf { int projection; } ubuf; -out gl_PerVertex { vec4 gl_Position; }; +out gl_PerVertex { vec4 gl_Position; float gl_PointSize; }; void main() { @@ -25,4 +25,6 @@ void main() } pos = v.xy * 1.37; + + gl_PointSize = 1.0; } diff --git a/src/quick/scenegraph/shaders_ng/visualization.vert.qsb b/src/quick/scenegraph/shaders_ng/visualization.vert.qsb index bd89847dd3..7ba27cb4b5 100644 Binary files a/src/quick/scenegraph/shaders_ng/visualization.vert.qsb and b/src/quick/scenegraph/shaders_ng/visualization.vert.qsb differ -- cgit v1.2.3 From 0aada37644762d4757f9f9b2a76e31389aa91b27 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 26 Aug 2019 13:31:58 +0200 Subject: Fix not printing logs with QSG_INFO when forcing rhi backend from C++ QQuickWindow::setScenegraphBackend() may be called before QQuickWindow gets a chance to create a render loop. If QSG_INFO (the env.var.) is used instead of the logging category (qt.scenegraph.general), some logs are not printed because the code that enables the logging category is not yet run. To prevent confusion, make sure the logging category gets enabled before the first potential qCDebug. In the worst case we check twice but that's fine. Change-Id: Ibfc0af05050adc9766c30a2d15c778b2a51823fe Reviewed-by: Andy Nichols --- src/quick/scenegraph/qsgrenderloop.cpp | 4 +--- src/quick/scenegraph/qsgrhisupport.cpp | 13 +++++++++++++ src/quick/scenegraph/qsgrhisupport_p.h | 2 ++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp index 58dfd97e03..08d1c726ab 100644 --- a/src/quick/scenegraph/qsgrenderloop.cpp +++ b/src/quick/scenegraph/qsgrenderloop.cpp @@ -214,9 +214,7 @@ QSGRenderLoop *QSGRenderLoop::instance() { if (!s_instance) { - // For compatibility with 5.3 and earlier's QSG_INFO environment variables - if (qEnvironmentVariableIsSet("QSG_INFO")) - const_cast(QSG_LOG_INFO()).setEnabled(QtDebugMsg, true); + QSGRhiSupport::checkEnvQSgInfo(); s_instance = QSGContext::createWindowManager(); #ifdef ENABLE_DEFAULT_BACKEND diff --git a/src/quick/scenegraph/qsgrhisupport.cpp b/src/quick/scenegraph/qsgrhisupport.cpp index 8bae24dc76..a92b6b0c84 100644 --- a/src/quick/scenegraph/qsgrhisupport.cpp +++ b/src/quick/scenegraph/qsgrhisupport.cpp @@ -109,6 +109,12 @@ void QSGRhiSupport::applySettings() { m_set = true; + // This is also done when creating the renderloop but we may be before that + // in case we get here due to a setScenegraphBackend() -> configure() early + // on in main(). Avoid losing info logs since troubleshooting gets + // confusing otherwise. + QSGRhiSupport::checkEnvQSgInfo(); + if (m_requested.valid) { // explicit rhi backend request from C++ (e.g. via QQuickWindow) m_enableRhi = m_requested.rhi; @@ -203,6 +209,13 @@ QSGRhiSupport *QSGRhiSupport::staticInst() return &inst; } +void QSGRhiSupport::checkEnvQSgInfo() +{ + // For compatibility with 5.3 and earlier's QSG_INFO environment variables + if (qEnvironmentVariableIsSet("QSG_INFO")) + const_cast(QSG_LOG_INFO()).setEnabled(QtDebugMsg, true); +} + void QSGRhiSupport::configure(QSGRendererInterface::GraphicsApi api) { Q_ASSERT(QSGRendererInterface::isApiRhiBased(api)); diff --git a/src/quick/scenegraph/qsgrhisupport_p.h b/src/quick/scenegraph/qsgrhisupport_p.h index 0e1881aa00..f2d5837bba 100644 --- a/src/quick/scenegraph/qsgrhisupport_p.h +++ b/src/quick/scenegraph/qsgrhisupport_p.h @@ -126,6 +126,8 @@ public: QImage grabAndBlockInCurrentFrame(QRhi *rhi, QRhiSwapChain *swapchain); + static void checkEnvQSgInfo(); + private: QSGRhiSupport(); void applySettings(); -- cgit v1.2.3 From 3ecfd166f352faf21ea425bb0509c9837c311bb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Wed, 31 Jul 2019 11:41:54 +0200 Subject: Fix qqmltypeloader autotest for android Change-Id: I7a1a3c225119c4ab972beccff68d0d4b764aab4d Task-number: QTBUG-73512 Reviewed-by: Simon Hausmann --- tests/auto/qml/qqmltypeloader/dummy_imports.qml | 9 +++++++++ .../auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp | 21 ++++++++++++++++++--- .../auto/qml/qqmltypeloader/tst_qqmltypeloader.pro | 1 + 3 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 tests/auto/qml/qqmltypeloader/dummy_imports.qml diff --git a/tests/auto/qml/qqmltypeloader/dummy_imports.qml b/tests/auto/qml/qqmltypeloader/dummy_imports.qml new file mode 100644 index 0000000000..a4684b2007 --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/dummy_imports.qml @@ -0,0 +1,9 @@ +// This file exists for the sole purpose for qmlimportscanner to find +// which modules it needs to extract for deployment. +// Otherwise, it fails to find the imports that are expressed in the +// C++ code belonging to the test. + +import QtQml 2.0 +import QtQuick 2.6 + +QtObject { } // This is needed in order to keep importscanner happy diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp index 2993b4b3c8..63a43eebad 100644 --- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp +++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp @@ -60,10 +60,16 @@ private slots: void implicitComponentModule(); void qrcRootPathUrl(); void implicitImport(); + +private: + void checkSingleton(const QString & dataDirectory); }; void tst_QQMLTypeLoader::testLoadComplete() { +#ifdef Q_OS_ANDROID + QSKIP("Loading dynamic plugins does not work on Android"); +#endif QQuickView *window = new QQuickView(); window->engine()->addImportPath(QT_TESTCASE_BUILDDIR); qDebug() << window->engine()->importPathList(); @@ -157,7 +163,7 @@ void tst_QQMLTypeLoader::trimCache3() QCOMPARE(loader.isTypeLoaded(testFileUrl("ComponentWithIncubator.qml")), false); } -static void checkSingleton(const QString &dataDirectory) +void tst_QQMLTypeLoader::checkSingleton(const QString &dataDirectory) { QQmlEngine engine; engine.addImportPath(dataDirectory); @@ -166,8 +172,8 @@ static void checkSingleton(const QString &dataDirectory) "import QtQuick 2.6\n" "import \"..\"\n" "Item { property int t: ValueSource.something }", - QUrl::fromLocalFile(dataDirectory + "/abc/Xyz.qml")); - QCOMPARE(component.status(), QQmlComponent::Ready); + testFileUrl("abc/Xyz.qml")); + QVERIFY2(component.status() == QQmlComponent::Ready, qPrintable(component.errorString())); QScopedPointer o(component.create()); QVERIFY(o.data()); QCOMPARE(o->property("t").toInt(), 10); @@ -389,6 +395,9 @@ public: void tst_QQMLTypeLoader::intercept() { +#ifdef Q_OS_ANDROID + QSKIP("Loading dynamic plugins does not work on Android"); +#endif qmlClearTypeRegistrations(); QQmlEngine engine; @@ -478,6 +487,9 @@ static void checkCleanCacheLoad(const QString &testCase) void tst_QQMLTypeLoader::multiSingletonModule() { +#ifdef Q_OS_ANDROID + QSKIP("Android seems to have problems with QProcess"); +#endif qmlClearTypeRegistrations(); QQmlEngine engine; engine.addImportPath(testFile("imports")); @@ -498,6 +510,9 @@ void tst_QQMLTypeLoader::multiSingletonModule() void tst_QQMLTypeLoader::implicitComponentModule() { +#ifdef Q_OS_ANDROID + QSKIP("Android seems to have problems with QProcess"); +#endif QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("implicitcomponent.qml")); QCOMPARE(component.status(), QQmlComponent::Ready); diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.pro b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.pro index 0352561e03..743f7cf3ac 100644 --- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.pro +++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.pro @@ -12,3 +12,4 @@ HEADERS += \ include (../../shared/util.pri) +TESTDATA = data/* -- cgit v1.2.3 From 54f31a64d01a138e72f79b9585cb90004bbe1e4a Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 29 Aug 2019 12:27:59 +0200 Subject: Avoid introducing rhiTexture() in the public API of QSGTexture MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no need for this. The few internal users can get it via QSGTexturePrivate. The original thinking was based on QRhi* being a public API, but that is not the case in the near future. So avoid introducing a public API relying on QRhiTexture. This of course makes it impossible to retrieve the native object under a QSGTexture (as textureId() is not used anymore when rendering with the RHI). For that, an alternative approach will be introduced later on. Change-Id: I0099b23424cafa4958f78c03300b0c934b60d92c Reviewed-by: Christian Strømme --- src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp | 2 +- src/quick/scenegraph/coreapi/qsgtexture.cpp | 38 ++++++++++------------- src/quick/scenegraph/coreapi/qsgtexture.h | 1 - src/quick/scenegraph/coreapi/qsgtexture_p.h | 3 +- src/quick/scenegraph/qsgdefaultglyphnode_p.cpp | 4 ++- 5 files changed, 23 insertions(+), 25 deletions(-) diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index 2441e14fda..336107a61d 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -3492,7 +3492,7 @@ void Renderer::updateMaterialDynamicData(ShaderManager::Shader *sms, } if (pd->textureBindingTable[binding] && pd->samplerBindingTable[binding]) { - QRhiTexture *texture = pd->textureBindingTable[binding]->rhiTexture(); + QRhiTexture *texture = QSGTexturePrivate::get(pd->textureBindingTable[binding])->rhiTexture(); // texture may be null if the update above failed for any reason, // or if the QSGTexture chose to return null intentionally. This is // valid and we still need to provide something to the shader. diff --git a/src/quick/scenegraph/coreapi/qsgtexture.cpp b/src/quick/scenegraph/coreapi/qsgtexture.cpp index cfd0cb9f06..c47401e5c0 100644 --- a/src/quick/scenegraph/coreapi/qsgtexture.cpp +++ b/src/quick/scenegraph/coreapi/qsgtexture.cpp @@ -695,27 +695,6 @@ void QSGTexture::updateBindOptions(bool force) // legacy (GL-only) #endif } -/*! - \return the QRhiTexture for this QSGTexture or null if there is none. - - Unlike textureId(), this function is not expected to create a new - QRhiTexture in case there is none. Just return null in that case. The - expectation towards the renderer is that a null texture leads to using a - transparent, dummy texture instead. - - \note This function is only used when running the graphics API independent - rendering path of the scene graph. - - \warning This function can only be called from the rendering thread. - - \since 5.14 - */ -QRhiTexture *QSGTexture::rhiTexture() const -{ - Q_D(const QSGTexture); - return d->rhiTexture(); -} - /*! Call this function to enqueue image upload operations to \a resourceUpdates, in case there are any pending ones. When there is no new @@ -762,6 +741,23 @@ int QSGTexturePrivate::comparisonKey() const return q->textureId(); // this is semantically wrong but at least compatible with existing, non-RHI-aware subclasses } +/*! + \internal + + \return the QRhiTexture for this QSGTexture or null if there is none. + + Unlike textureId(), this function is not expected to create a new + QRhiTexture in case there is none. Just return null in that case. The + expectation towards the renderer is that a null texture leads to using a + transparent, dummy texture instead. + + \note This function is only used when running the graphics API independent + rendering path of the scene graph. + + \warning This function can only be called from the rendering thread. + + \since 5.14 + */ QRhiTexture *QSGTexturePrivate::rhiTexture() const { return nullptr; diff --git a/src/quick/scenegraph/coreapi/qsgtexture.h b/src/quick/scenegraph/coreapi/qsgtexture.h index f2b0e902f3..4cd2a5cddd 100644 --- a/src/quick/scenegraph/coreapi/qsgtexture.h +++ b/src/quick/scenegraph/coreapi/qsgtexture.h @@ -113,7 +113,6 @@ public: // ### Qt 6: make these virtual int comparisonKey() const; - QRhiTexture *rhiTexture() const; void updateRhiTexture(QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates); // ### Qt 6: make this an argument for removedFromAtlas() diff --git a/src/quick/scenegraph/coreapi/qsgtexture_p.h b/src/quick/scenegraph/coreapi/qsgtexture_p.h index 1d248b0305..cb59d32012 100644 --- a/src/quick/scenegraph/coreapi/qsgtexture_p.h +++ b/src/quick/scenegraph/coreapi/qsgtexture_p.h @@ -83,9 +83,10 @@ public: void resetDirtySamplerOptions(); bool hasDirtySamplerOptions() const; + virtual QRhiTexture *rhiTexture() const; + // ### Qt 6: these should be virtuals in the public class instead virtual int comparisonKey() const; // ### Qt 6: pure virtual - virtual QRhiTexture *rhiTexture() const; virtual void updateRhiTexture(QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates); QRhiResourceUpdateBatch *workResourceUpdateBatch = nullptr; // ### Qt 6: remove diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp index db889c3102..8fc8c711c6 100644 --- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp +++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp @@ -451,7 +451,9 @@ bool QSGTextMaskRhiShader::updateUniformData(const RenderState &state, changed = true; } - if (updated || !oldMat || oldMat->texture()->rhiTexture() != mat->texture()->rhiTexture()) { + QRhiTexture *oldRtex = oldMat ? QSGTexturePrivate::get(oldMat->texture())->rhiTexture() : nullptr; + QRhiTexture *newRtex = QSGTexturePrivate::get(mat->texture())->rhiTexture(); + if (updated || !oldMat || oldRtex != newRtex) { const QVector2D textureScale = QVector2D(1.0f / mat->rhiGlyphCache()->width(), 1.0f / mat->rhiGlyphCache()->height()); memcpy(buf->data() + 64 + 16, &textureScale, 8); -- cgit v1.2.3 From 0cf0729dd0a4d958fafd3acd6c6b8100213370fd Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Thu, 22 Aug 2019 11:32:49 +0200 Subject: Fix build with -no-feature-quick-path Change-Id: I7ed2c190ffe9ddd83aeee28de3c5d87269ec53ee Reviewed-by: Paolo Angelelli --- src/quick/items/qquickitemsmodule.cpp | 2 ++ src/src.pro | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index 3927a440e8..f2098f6732 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -480,6 +480,8 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) #if QT_CONFIG(quick_itemview) qmlRegisterUncreatableType(uri, 2, 13, itemViewName, itemViewMessage); +#endif +#if QT_CONFIG(quick_pathview) qmlRegisterType(uri, 2, 13, "PathView"); #endif #if QT_CONFIG(quick_gridview) diff --git a/src/src.pro b/src/src.pro index b1e0a72c9f..98e1779dc5 100644 --- a/src/src.pro +++ b/src/src.pro @@ -11,9 +11,10 @@ qtConfig(qml-worker-script): \ SUBDIRS += qmlworkerscript qtHaveModule(gui):qtConfig(qml-animation) { - SUBDIRS += \ - quick \ - quickshapes + SUBDIRS += quick + + qtConfig(quick-path): \ + SUBDIRS += quickshapes qtConfig(testlib): \ SUBDIRS += qmltest -- cgit v1.2.3 From 08c365ca12abb3d641d923f98380ed6d8df3b05b Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 30 Aug 2019 09:14:53 +0200 Subject: Add a note to QSGEngine about its incompatibility with the RHI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Id9d6ce4a531d2cd1b79b3bb9224a5567ead42799 Reviewed-by: Christian Strømme --- src/quick/scenegraph/util/qsgengine.cpp | 4 ++++ src/quick/scenegraph/util/qsgengine.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/quick/scenegraph/util/qsgengine.cpp b/src/quick/scenegraph/util/qsgengine.cpp index c05005c467..4880d98871 100644 --- a/src/quick/scenegraph/util/qsgengine.cpp +++ b/src/quick/scenegraph/util/qsgengine.cpp @@ -69,6 +69,10 @@ QT_BEGIN_NAMESPACE Most of the time you will instead want to subclass QQuickItem and insert your QSGNode in a normal QtQuick scene by overriding QQuickItem::updatePaintNode(). + \warning This class is only suitable when working directly with OpenGL. It + is not compatible with the \l{Scene Graph Adaptations}{RHI-based rendering + path}. + \sa QSGAbstractRenderer */ diff --git a/src/quick/scenegraph/util/qsgengine.h b/src/quick/scenegraph/util/qsgengine.h index e48b7784ae..c5a59b47e7 100644 --- a/src/quick/scenegraph/util/qsgengine.h +++ b/src/quick/scenegraph/util/qsgengine.h @@ -54,6 +54,8 @@ class QSGRectangleNode; class QSGImageNode; class QSGNinePatchNode; +// ### Qt 6: Remove or redesign. + class Q_QUICK_EXPORT QSGEngine : public QObject { Q_OBJECT -- cgit v1.2.3 From cefab21cbd464171f0f90de9ac12c6174ecd7d59 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 30 Aug 2019 11:48:42 +0200 Subject: QQuickFbo: add the RHI warning This class will probably go away in Qt 6. "Probably", because it is not yet clear if/how an alternative will be provided. Change-Id: Iba205c394a97bf8d2c1001f8f42ad26be6841b09 Reviewed-by: Andy Nichols --- src/quick/items/qquickframebufferobject.cpp | 4 ++++ src/quick/items/qquickframebufferobject.h | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/quick/items/qquickframebufferobject.cpp b/src/quick/items/qquickframebufferobject.cpp index 48f8b8db5c..190bc6853c 100644 --- a/src/quick/items/qquickframebufferobject.cpp +++ b/src/quick/items/qquickframebufferobject.cpp @@ -109,6 +109,10 @@ public: * and can be used directly in \l {ShaderEffect}{ShaderEffects} and other * classes that consume texture providers. * + * \warning This class is only suitable when working directly with OpenGL. It + * is not compatible with the \l{Scene Graph Adaptations}{RHI-based rendering + * path}. + * * \sa {Scene Graph - Rendering FBOs}, {Scene Graph and Rendering} */ diff --git a/src/quick/items/qquickframebufferobject.h b/src/quick/items/qquickframebufferobject.h index d66ca40b3a..db143e48cf 100644 --- a/src/quick/items/qquickframebufferobject.h +++ b/src/quick/items/qquickframebufferobject.h @@ -44,11 +44,12 @@ QT_BEGIN_NAMESPACE - class QOpenGLFramebufferObject; class QQuickFramebufferObjectPrivate; class QSGFramebufferObjectNode; +// ### Qt 6: To be removed. To be seen if an alternative will need to be introduced. + class Q_QUICK_EXPORT QQuickFramebufferObject : public QQuickItem { Q_OBJECT -- cgit v1.2.3 From a6323d1ad8ad7af585ed76a5a3a97a48e955ff91 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 29 Aug 2019 14:20:39 +0200 Subject: Add a createTextureFromId() alternative Say hello to createTextureFromNativeObject(). This is the future replaecment for createTextureFromId(), and is capable of operating on both the direct OpenGL and the RHI code paths. In practice this allows creating a QSGTexture that wraps - but does not own - an existing VkImage, ID3D11Texture2D*, MTLTexture*, or GLuint. Change-Id: I500ee4c76da67eca1a70599a30b03d7b126b570d Reviewed-by: Andy Nichols --- src/quick/items/qquickwindow.cpp | 116 +++++++++++++++++++-- src/quick/items/qquickwindow.h | 10 ++ src/quick/scenegraph/scenegraph.pri | 2 + src/quick/scenegraph/util/qsgplaintexture.cpp | 19 ++++ src/quick/scenegraph/util/qsgplaintexture_p.h | 4 + .../util/qsgrhinativetextureimporter.cpp | 104 ++++++++++++++++++ .../util/qsgrhinativetextureimporter_p.h | 70 +++++++++++++ 7 files changed, 318 insertions(+), 7 deletions(-) create mode 100644 src/quick/scenegraph/util/qsgrhinativetextureimporter.cpp create mode 100644 src/quick/scenegraph/util/qsgrhinativetextureimporter_p.h diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 8b5e2a012a..27e2a4572e 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -4450,7 +4450,8 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image, CreateText \note This function only has an effect when using the default OpenGL scene graph adaptation. - \note This function has no effect when running on the RHI graphics abstraction. + \note This function has no effect when running on the RHI graphics + abstraction. Use createTextureFromNativeObject() instead. \sa sceneGraphInitialized(), QSGTexture */ @@ -4458,19 +4459,120 @@ QSGTexture *QQuickWindow::createTextureFromId(uint id, const QSize &size, Create { #if QT_CONFIG(opengl) Q_D(const QQuickWindow); - if (!d->rhi && openglContext()) { - QSGPlainTexture *texture = new QSGPlainTexture(); - texture->setTextureId(id); + if (!d->rhi) { + if (openglContext()) { + QSGPlainTexture *texture = new QSGPlainTexture(); + texture->setTextureId(id); + texture->setHasAlphaChannel(options & TextureHasAlphaChannel); + texture->setOwnsTexture(options & TextureOwnsGLTexture); + texture->setTextureSize(size); + return texture; + } + } else { + qWarning("createTextureFromId() must not be called when running on the RHI. " + "Use createTextureFromNativeObject() instead."); + } +#else + Q_UNUSED(id) + Q_UNUSED(size) + Q_UNUSED(options) +#endif + return nullptr; +} + +/*! + \enum QQuickWindow::NativeObjectType + \since 5.14 + + Specifies the type of the native object passed to functions such as + createTextureFromNativeObject(). + + \value NativeObjectTexture The native object is a 2D texture (OpenGL, + Direct3D 11, Metal) or image (Vulkan). + */ + +/*! + Creates a new QSGTexture object from an existing native object. + + The native object is wrapped, but not owned, by the resulting QSGTexture. + The caller of the function is responsible for deleting the returned + QSGTexture, but that will not destroy the underlying native object. + + \a type specifies the type of the object. In practice the type is + NativeObjectTexture, indicating that the native object is a texture or + image of the underlying graphics API. Other types may be introduced in the + future. + + This function is currently suitable for 2D RGBA textures only. + + Unlike createTextureFromId(), this function supports both direct OpenGL + usage and the RHI abstracted rendering path. + + \warning This function will return null if the scenegraph has not yet been + initialized. + + Use \a options to customize the texture attributes. Only the + TextureHasAlphaChannel and TextureHasMipmaps are taken into account here. + + \warning Unlike createTextureFromId(), this function never takes ownership + of the native object, and the TextureOwnsGLTexture flag is ignored. + + \a size specifies the size in pixels. + + \a nativeObjectPtr is a pointer to the native object handle. With OpenGL, + the native handle is a GLuint value, so \a nativeObjectPtr is then a + pointer to a GLuint. With Vulkan, the native handle is a VkImage, so \a + nativeObjectPtr is a pointer to a VkImage. With Direct3D 11 and Metal \a + nativeObjectPtr is a pointer to a ID3D11Texture2D or MTLTexture pointer. + + \note Pay attention to the fact that \a nativeObjectPtr is always a pointer + to the native texture handle type, even if the native type itself is a + pointer. + + \a nativeLayout is only used for APIs like Vulkan. When applicable, it must + specify the current image layout, such as, a VkImageLayout value. + + \sa sceneGraphInitialized(), QSGTextures + + \since 5.14 + */ +QSGTexture *QQuickWindow::createTextureFromNativeObject(NativeObjectType type, + const void *nativeObjectPtr, + int nativeLayout, + const QSize &size, + CreateTextureOptions options) const +{ + if (type != NativeObjectTexture) { + qWarning("createTextureFromNativeObject: only textures are supported"); + return nullptr; + } + +#if QT_CONFIG(opengl) /* || QT_CONFIG(vulkan) || defined(Q_OS_WIN) || defined(Q_OS_DARWIN) */ + Q_D(const QQuickWindow); + if (d->rhi) { + QSGPlainTexture *texture = new QSGPlainTexture; + texture->setTextureFromNativeObject(d->rhi, type, nativeObjectPtr, nativeLayout, + size, options.testFlag(TextureHasMipmaps)); + texture->setHasAlphaChannel(options & TextureHasAlphaChannel); + // note that the QRhiTexture does not (and cannot) own the native object + texture->setOwnsTexture(true); // texture meaning the QRhiTexture here, not the native object + texture->setTextureSize(size); + return texture; + } else if (openglContext()) { + QSGPlainTexture *texture = new QSGPlainTexture; + texture->setTextureId(*reinterpret_cast(nativeObjectPtr)); texture->setHasAlphaChannel(options & TextureHasAlphaChannel); texture->setOwnsTexture(options & TextureOwnsGLTexture); texture->setTextureSize(size); return texture; } #else - Q_UNUSED(id) - Q_UNUSED(size) - Q_UNUSED(options) + Q_UNUSED(nativeObjectPtr); + Q_UNUSED(nativeLayout); + Q_UNUSED(size); + Q_UNUSED(options); #endif + return nullptr; } diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h index ab3046611f..9dbff88f0d 100644 --- a/src/quick/items/qquickwindow.h +++ b/src/quick/items/qquickwindow.h @@ -109,6 +109,11 @@ public: }; Q_ENUM(TextRenderType) + enum NativeObjectType { + NativeObjectTexture + }; + Q_ENUM(NativeObjectType) + explicit QQuickWindow(QWindow *parent = nullptr); explicit QQuickWindow(QQuickRenderControl *renderControl); @@ -153,6 +158,11 @@ public: QSGTexture *createTextureFromImage(const QImage &image) const; QSGTexture *createTextureFromImage(const QImage &image, CreateTextureOptions options) const; QSGTexture *createTextureFromId(uint id, const QSize &size, CreateTextureOptions options = CreateTextureOption()) const; + QSGTexture *createTextureFromNativeObject(NativeObjectType type, + const void *nativeObjectPtr, + int nativeLayout, + const QSize &size, + CreateTextureOptions options = CreateTextureOption()) const; void setClearBeforeRendering(bool enabled); bool clearBeforeRendering() const; diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri index ee9ea0f5ed..c345f3b16d 100644 --- a/src/quick/scenegraph/scenegraph.pri +++ b/src/quick/scenegraph/scenegraph.pri @@ -53,6 +53,7 @@ HEADERS += \ $$PWD/util/qsgengine.h \ $$PWD/util/qsgengine_p.h \ $$PWD/util/qsgplaintexture_p.h \ + $$PWD/util/qsgrhinativetextureimporter_p.h \ $$PWD/util/qsgsimplerectnode.h \ $$PWD/util/qsgsimpletexturenode.h \ $$PWD/util/qsgtextureprovider.h \ @@ -69,6 +70,7 @@ SOURCES += \ $$PWD/util/qsgareaallocator.cpp \ $$PWD/util/qsgengine.cpp \ $$PWD/util/qsgplaintexture.cpp \ + $$PWD/util/qsgrhinativetextureimporter.cpp \ $$PWD/util/qsgsimplerectnode.cpp \ $$PWD/util/qsgsimpletexturenode.cpp \ $$PWD/util/qsgtextureprovider.cpp \ diff --git a/src/quick/scenegraph/util/qsgplaintexture.cpp b/src/quick/scenegraph/util/qsgplaintexture.cpp index 72313db836..fdebe03494 100644 --- a/src/quick/scenegraph/util/qsgplaintexture.cpp +++ b/src/quick/scenegraph/util/qsgplaintexture.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "qsgplaintexture_p.h" +#include "qsgrhinativetextureimporter_p.h" #include #include #include @@ -274,6 +275,24 @@ void QSGPlainTexture::setTexture(QRhiTexture *texture) // RHI only m_mipmaps_generated = false; } +void QSGPlainTexture::setTextureFromNativeObject(QRhi *rhi, QQuickWindow::NativeObjectType type, + const void *nativeObjectPtr, int nativeLayout, + const QSize &size, bool mipmap) +{ + Q_UNUSED(type); + + QRhiTexture::Flags flags = 0; + if (mipmap) + flags |= QRhiTexture::MipMapped | QRhiTexture::UsedWithGenerateMips; + + QRhiTexture *t = rhi->newTexture(QRhiTexture::RGBA8, size, 1, flags); + + // ownership of the native object is never taken + QSGRhiNativeTextureImporter::buildWrapper(rhi, t, nativeObjectPtr, nativeLayout); + + setTexture(t); +} + int QSGPlainTexturePrivate::comparisonKey() const { Q_Q(const QSGPlainTexture); diff --git a/src/quick/scenegraph/util/qsgplaintexture_p.h b/src/quick/scenegraph/util/qsgplaintexture_p.h index 69c0153f9a..1eb0b59d2e 100644 --- a/src/quick/scenegraph/util/qsgplaintexture_p.h +++ b/src/quick/scenegraph/util/qsgplaintexture_p.h @@ -53,6 +53,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -85,6 +86,9 @@ public: void bind() override; void setTexture(QRhiTexture *texture); + void setTextureFromNativeObject(QRhi *rhi, QQuickWindow::NativeObjectType type, + const void *nativeObjectPtr, int nativeLayout, + const QSize &size, bool mipmap); static QSGPlainTexture *fromImage(const QImage &image) { QSGPlainTexture *t = new QSGPlainTexture(); diff --git a/src/quick/scenegraph/util/qsgrhinativetextureimporter.cpp b/src/quick/scenegraph/util/qsgrhinativetextureimporter.cpp new file mode 100644 index 0000000000..7a7c19f587 --- /dev/null +++ b/src/quick/scenegraph/util/qsgrhinativetextureimporter.cpp @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgrhinativetextureimporter_p.h" +#include // to get all the relevant qrhi headers + +QT_BEGIN_NAMESPACE + +void QSGRhiNativeTextureImporter::buildWrapper(QRhi *rhi, QRhiTexture *t, + const void *nativeObjectPtr, int nativeLayout) +{ +#if !QT_CONFIG(vulkan) + Q_UNUSED(nativeLayout); +#endif +#if !QT_CONFIG(opengl) && !QT_CONFIG(vulkan) && !defined(Q_OS_WIN) && !defined(Q_OS_DARWIN) + Q_UNUSED(nativeObjectPtr); +#endif + + switch (rhi->backend()) { + case QRhi::OpenGLES2: + { +#if QT_CONFIG(opengl) + QRhiGles2TextureNativeHandles h; + h.texture = *reinterpret_cast(nativeObjectPtr); + t->buildFrom(&h); +#endif + } + break; + case QRhi::Vulkan: + { +#if QT_CONFIG(vulkan) + QRhiVulkanTextureNativeHandles h; + h.image = *reinterpret_cast(nativeObjectPtr); + h.layout = VkImageLayout(nativeLayout); + t->buildFrom(&h); +#endif + } + break; + case QRhi::D3D11: + { +#ifdef Q_OS_WIN + QRhiD3D11TextureNativeHandles h; + h.texture = *reinterpret_cast(nativeObjectPtr); + t->buildFrom(&h); +#endif + } + break; + case QRhi::Metal: + { +#ifdef Q_OS_DARWIN + QRhiMetalTextureNativeHandles h; + h.texture = *reinterpret_cast(nativeObjectPtr); + t->buildFrom(&h); +#endif + } + break; + case QRhi::Null: + t->build(); + break; + default: + qWarning("QSGRhiNativeTextureImporter: encountered an unsupported QRhi backend (%d)", + int(rhi->backend())); + t->build(); + break; + } +} + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgrhinativetextureimporter_p.h b/src/quick/scenegraph/util/qsgrhinativetextureimporter_p.h new file mode 100644 index 0000000000..e811109a94 --- /dev/null +++ b/src/quick/scenegraph/util/qsgrhinativetextureimporter_p.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGRHINATIVETEXTUREIMPORTER_P_H +#define QSGRHINATIVETEXTUREIMPORTER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QRhi; +class QRhiTexture; + +class QSGRhiNativeTextureImporter +{ +public: + static void buildWrapper(QRhi *rhi, QRhiTexture *t, + const void *nativeObjectPtr, int nativeLayout); +}; + +QT_END_NAMESPACE + +#endif // QSGRHINATIVETEXTUREIMPORTER_P_H -- cgit v1.2.3 From 6e721910685c08b8b8a64722018ef2d847004de6 Mon Sep 17 00:00:00 2001 From: Tasuku Suzuki Date: Sat, 17 Aug 2019 17:00:42 +0900 Subject: Fix build without features.easingcurve Change-Id: If8de1f1a61fda051fb5585b8966bc1bfe94c97a3 Reviewed-by: Volker Hilsheimer --- src/qml/qml/qqmlvaluetype.cpp | 7 +++++++ src/qml/qml/qqmlvaluetype_p.h | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp index 88f7b69dc2..2225191a9d 100644 --- a/src/qml/qml/qqmlvaluetype.cpp +++ b/src/qml/qml/qqmlvaluetype.cpp @@ -122,8 +122,10 @@ const QMetaObject *QQmlValueTypeFactoryImpl::metaObjectForMetaType(int t) return &QQmlRectValueType::staticMetaObject; case QVariant::RectF: return &QQmlRectFValueType::staticMetaObject; +#if QT_CONFIG(easingcurve) case QVariant::EasingCurve: return &QQmlEasingValueType::staticMetaObject; +#endif #if QT_CONFIG(qml_itemmodel) case QVariant::ModelIndex: return &QQmlModelIndexValueType::staticMetaObject; @@ -201,7 +203,9 @@ const QMetaObject *QQmlValueTypeFactory::metaObjectForMetaType(int type) void QQmlValueTypeFactory::registerValueTypes(const char *uri, int versionMajor, int versionMinor) { +#if QT_CONFIG(easingcurve) qmlRegisterValueTypeEnums(uri, versionMajor, versionMinor, "Easing"); +#endif } QQmlValueType::QQmlValueType(int typeId, const QMetaObject *gadgetMetaObject) @@ -489,6 +493,7 @@ int QQmlRectValueType::bottom() const return v.bottom(); } +#if QT_CONFIG(easingcurve) QQmlEasingValueType::Type QQmlEasingValueType::type() const { return (QQmlEasingValueType::Type)v.type(); @@ -572,6 +577,8 @@ QVariantList QQmlEasingValueType::bezierCurve() const rv << QVariant(point.x()) << QVariant(point.y()); return rv; } +#endif // easingcurve + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h index 89f1b71d61..75150b3f32 100644 --- a/src/qml/qml/qqmlvaluetype_p.h +++ b/src/qml/qml/qqmlvaluetype_p.h @@ -58,7 +58,9 @@ #include #include +#if QT_CONFIG(easingcurve) #include +#endif #include QT_BEGIN_NAMESPACE @@ -210,6 +212,7 @@ public: int bottom() const; }; +#if QT_CONFIG(easingcurve) struct QQmlEasingValueType { QEasingCurve v; @@ -260,6 +263,7 @@ public: void setBezierCurve(const QVariantList &); QVariantList bezierCurve() const; }; +#endif template int qmlRegisterValueTypeEnums(const char *uri, int versionMajor, int versionMinor, const char *qmlName) -- cgit v1.2.3 From 6ed139172d9ab82e1a22de71a665e023e87b3c58 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 28 Aug 2019 13:05:06 +0200 Subject: Fix pedantic warnings in QQuickImage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - semicolon after switch is not necessary - a switch that covers all possible cases should not have a default case: that way if someone adds another enum value, she needs to think about what it means in that switch - hopefully it was not intentional to ensure that targetRect has integral size in the PreserveAspectCrop case; it's not an explicit cast, so it looks like a mistake Change-Id: Ie7525137e826ed3ea03ac1dc9d2563e791379b42 Reviewed-by: Jan Arve Sæther --- src/quick/items/qquickimage.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp index 87b848b21b..c7e7ccea55 100644 --- a/src/quick/items/qquickimage.cpp +++ b/src/quick/items/qquickimage.cpp @@ -687,7 +687,6 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) yOffset = qCeil(height() - pixHeight); switch (d->fillMode) { - default: case Stretch: targetRect = QRectF(0, 0, width(), height()); sourceRect = d->pix.rect(); @@ -699,7 +698,7 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) break; case PreserveAspectCrop: { - targetRect = QRect(0, 0, width(), height()); + targetRect = QRectF(0, 0, width(), height()); qreal wscale = width() / qreal(d->pix.width()); qreal hscale = height() / qreal(d->pix.height()); @@ -751,7 +750,7 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) targetRect = QRectF(x + xOffset, y + yOffset, w, h); sourceRect = QRectF(x, y, w, h); break; - }; + } qreal nsWidth = (hWrap == QSGTexture::Repeat || d->fillMode == Pad) ? d->pix.width() / d->devicePixelRatio : d->pix.width(); qreal nsHeight = (vWrap == QSGTexture::Repeat || d->fillMode == Pad) ? d->pix.height() / d->devicePixelRatio : d->pix.height(); -- cgit v1.2.3 From 426f3035a3753800ce340a83bdf8db13922f4cae Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 2 Sep 2019 15:30:17 +0200 Subject: Visit lists iteratively when parsing QML Change-Id: I243d12b75a07ac04560b444c326bff77d0dc642c Fixes: QTBUG-74087 Reviewed-by: Fabian Kosmale Reviewed-by: Simon Hausmann --- src/qml/parser/qqmljsast.cpp | 73 +++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp index 700c191499..b63b2191b9 100644 --- a/src/qml/parser/qqmljsast.cpp +++ b/src/qml/parser/qqmljsast.cpp @@ -238,12 +238,11 @@ void StringLiteral::accept0(Visitor *visitor) void TemplateLiteral::accept0(Visitor *visitor) { - if (visitor->visit(this)) { - if (next) - accept(next, visitor); + bool accepted = true; + for (TemplateLiteral *it = this; it && accepted; it = it->next) { + accepted = visitor->visit(it); + visitor->endVisit(it); } - - visitor->endVisit(this); } void NumericLiteral::accept0(Visitor *visitor) @@ -1015,13 +1014,13 @@ BoundNames FormalParameterList::boundNames() const void FormalParameterList::accept0(Visitor *visitor) { - if (visitor->visit(this)) { - accept(element, visitor); - if (next) - accept(next, visitor); + bool accepted = true; + for (FormalParameterList *it = this; it && accepted; it = it->next) { + accepted = visitor->visit(it); + if (accepted) + accept(it->element, visitor); + visitor->endVisit(it); } - - visitor->endVisit(this); } FormalParameterList *FormalParameterList::finish(QQmlJS::MemoryPool *pool) @@ -1321,12 +1320,14 @@ void UiPragma::accept0(Visitor *visitor) void UiHeaderItemList::accept0(Visitor *visitor) { - if (visitor->visit(this)) { - accept(headerItem, visitor); - accept(next, visitor); - } + bool accepted = true; + for (UiHeaderItemList *it = this; it && accepted; it = it->next) { + accepted = visitor->visit(it); + if (accepted) + accept(it->headerItem, visitor); - visitor->endVisit(this); + visitor->endVisit(it); + } } @@ -1391,14 +1392,15 @@ void PatternElement::boundNames(BoundNames *names) void PatternElementList::accept0(Visitor *visitor) { - if (visitor->visit(this)) { - accept(elision, visitor); - accept(element, visitor); - if (next) - accept(next, visitor); + bool accepted = true; + for (PatternElementList *it = this; it && accepted; it = it->next) { + accepted = visitor->visit(it); + if (accepted) { + accept(it->elision, visitor); + accept(it->element, visitor); + } + visitor->endVisit(it); } - - visitor->endVisit(this); } void PatternElementList::boundNames(BoundNames *names) @@ -1428,13 +1430,13 @@ void PatternProperty::boundNames(BoundNames *names) void PatternPropertyList::accept0(Visitor *visitor) { - if (visitor->visit(this)) { - accept(property, visitor); - if (next) - accept(next, visitor); + bool accepted = true; + for (PatternPropertyList *it = this; it && accepted; it = it->next) { + accepted = visitor->visit(it); + if (accepted) + accept(it->property, visitor); + visitor->endVisit(it); } - - visitor->endVisit(this); } void PatternPropertyList::boundNames(BoundNames *names) @@ -1479,13 +1481,14 @@ void ClassDeclaration::accept0(Visitor *visitor) void ClassElementList::accept0(Visitor *visitor) { - if (visitor->visit(this)) { - accept(property, visitor); - if (next) - accept(next, visitor); - } + bool accepted = true; + for (ClassElementList *it = this; it && accepted; it = it->next) { + accepted = visitor->visit(it); + if (accepted) + accept(it->property, visitor); - visitor->endVisit(this); + visitor->endVisit(it); + } } ClassElementList *ClassElementList::finish() -- cgit v1.2.3 From 6dc319155a282cd274a93887c5b83c8ed8b82d90 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 16 Aug 2019 05:51:02 +0200 Subject: Enable PathPolyline to take a QPolygonF or QVector path If a C++ model object can make a vector of points available directly, and it is bound to a PathPolyline's path to provide the view layer, it's a waste of time to convert it to a QVariantList and back again. Changing the type of the property to QVariant instead of QVariantList enables an extensible set of supported types. Task-number: QTBUG-77929 Change-Id: I2453b59e047ec3310070e943f6934c9ddcd1ffaa Reviewed-by: Paolo Angelelli --- src/quick/util/qquickpath.cpp | 40 +++++---- src/quick/util/qquickpath_p.h | 6 +- tests/auto/quick/qquickshape/data/polyline.png | Bin 0 -> 757 bytes tests/auto/quick/qquickshape/data/polyline.qml | 52 ++++++++++++ tests/auto/quick/qquickshape/tst_qquickshape.cpp | 102 +++++++++++++++++++++++ 5 files changed, 182 insertions(+), 18 deletions(-) create mode 100644 tests/auto/quick/qquickshape/data/polyline.png create mode 100644 tests/auto/quick/qquickshape/data/polyline.qml diff --git a/src/quick/util/qquickpath.cpp b/src/quick/util/qquickpath.cpp index d246ee7910..6d4e469e44 100644 --- a/src/quick/util/qquickpath.cpp +++ b/src/quick/util/qquickpath.cpp @@ -2397,32 +2397,42 @@ void QQuickPathPercent::setValue(qreal value) \qmlproperty list QtQuick::PathPolyline::path This property defines the vertices of the polyline. + + It can be a JS array of points constructed with \c Qt.point(), + a QList or QVector of QPointF, or QPolygonF. + If you are binding this to a custom property in some C++ object, + QPolygonF is the most appropriate type to use. */ QQuickPathPolyline::QQuickPathPolyline(QObject *parent) : QQuickCurve(parent) { } -QVariantList QQuickPathPolyline::path() const +QVariant QQuickPathPolyline::path() const { - QVariantList res; - for (int i = 0; i < m_path.length(); ++i) { - const QPointF &c = m_path.at(i); - res.append(QVariant::fromValue(c)); - } - - return res; + return QVariant::fromValue(m_path); } -void QQuickPathPolyline::setPath(const QVariantList &path) +void QQuickPathPolyline::setPath(const QVariant &path) { - QVector pathList; - for (int i = 0; i < path.length(); ++i) { - const QPointF c = path.at(i).toPointF(); - pathList.append(c); + if (path.type() == QVariant::PolygonF) { + setPath(path.value()); + } else if (path.canConvert>()) { + setPath(path.value>()); + } else if (path.canConvert()) { + // This handles cases other than QPolygonF or QVector, such as + // QList, QVector, QVariantList of QPointF, QVariantList of QPoint. + QVector pathList; + QVariantList vl = path.value(); + // If path is a QJSValue, e.g. coming from a JS array of Qt.point() in QML, + // then path.value() is inefficient. + // TODO We should be able to iterate over path.value() eventually + for (const QVariant &v : vl) + pathList.append(v.toPointF()); + setPath(pathList); + } else { + qWarning() << "PathPolyline: path of type" << path.type() << "not supported"; } - - setPath(pathList); } void QQuickPathPolyline::setPath(const QVector &path) diff --git a/src/quick/util/qquickpath_p.h b/src/quick/util/qquickpath_p.h index 92607a6c1e..e37a2e2dce 100644 --- a/src/quick/util/qquickpath_p.h +++ b/src/quick/util/qquickpath_p.h @@ -428,12 +428,12 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPathPolyline : public QQuickCurve { Q_OBJECT Q_PROPERTY(QPointF start READ start NOTIFY startChanged) - Q_PROPERTY(QVariantList path READ path WRITE setPath NOTIFY pathChanged) + Q_PROPERTY(QVariant path READ path WRITE setPath NOTIFY pathChanged) public: QQuickPathPolyline(QObject *parent=nullptr); - QVariantList path() const; - void setPath(const QVariantList &path); + QVariant path() const; + void setPath(const QVariant &path); void setPath(const QVector &path); QPointF start() const; void addToPath(QPainterPath &path, const QQuickPathData &data) override; diff --git a/tests/auto/quick/qquickshape/data/polyline.png b/tests/auto/quick/qquickshape/data/polyline.png new file mode 100644 index 0000000000..00123fba44 Binary files /dev/null and b/tests/auto/quick/qquickshape/data/polyline.png differ diff --git a/tests/auto/quick/qquickshape/data/polyline.qml b/tests/auto/quick/qquickshape/data/polyline.qml new file mode 100644 index 0000000000..e62d952ae7 --- /dev/null +++ b/tests/auto/quick/qquickshape/data/polyline.qml @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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$ +** +****************************************************************************/ + +import QtQuick 2.14 +import QtQuick.Shapes 1.14 + +Shape { + width: 200 + height: 150 + vendorExtensionsEnabled: false + objectName: "shape" + id: shape + property alias path: polyline.path + property point vertexBeingChecked; + + function checkVertexAt(i) { + vertexBeingChecked = polyline.path[i] + } + + ShapePath { + strokeWidth: 4 + strokeColor: "green" + PathPolyline { + id: polyline + } + } +} diff --git a/tests/auto/quick/qquickshape/tst_qquickshape.cpp b/tests/auto/quick/qquickshape/tst_qquickshape.cpp index b3b8d2d148..69b65f0ec9 100644 --- a/tests/auto/quick/qquickshape/tst_qquickshape.cpp +++ b/tests/auto/quick/qquickshape/tst_qquickshape.cpp @@ -60,6 +60,11 @@ private slots: void conicalGrad(); void renderPolyline(); void renderMultiline(); + void polylineDataTypes_data(); + void polylineDataTypes(); + +private: + QVector m_lowPolyLogo; }; tst_QQuickShape::tst_QQuickShape() @@ -75,6 +80,29 @@ tst_QQuickShape::tst_QQuickShape() qmlRegisterType(uri, 1, 0, "RadialGradient"); qmlRegisterType(uri, 1, 0, "ConicalGradient"); qmlRegisterType(uri, 1, 0, "PathPolyline"); + + m_lowPolyLogo << (QPolygonF() << + QPointF(20, 0) << + QPointF(140, 0) << + QPointF(140, 80) << + QPointF(120, 100) << + QPointF(0, 100) << + QPointF(0, 20) << + QPointF(20, 0) ) + << (QPolygonF() << QPointF(20, 80) << + QPointF(60, 80) << + QPointF(80, 60) << + QPointF(80, 20) << + QPointF(40, 20) << + QPointF(20, 40) << + QPointF(20, 80) ) + << (QPolygonF() << QPointF(80, 80) << + QPointF(70, 70) ) + << (QPolygonF() << QPointF(120, 80) << + QPointF(100, 60) << + QPointF(100, 20) ) + << (QPolygonF() << QPointF(100, 40) << + QPointF(120, 40) ); } void tst_QQuickShape::initValues() @@ -373,6 +401,80 @@ void tst_QQuickShape::renderMultiline() QVERIFY2(res, qPrintable(errorMessage)); } +void tst_QQuickShape::polylineDataTypes_data() +{ + QTest::addColumn("path"); + + QTest::newRow("polygon") << QVariant::fromValue(m_lowPolyLogo.first()); + { + QVector points; + points << m_lowPolyLogo.first(); + QTest::newRow("vector of points") << QVariant::fromValue(points); + } + { + QList points; + for (const auto &point : m_lowPolyLogo.first()) + points << point; + QTest::newRow("list of points") << QVariant::fromValue(points); + } + { + QVariantList points; + for (const auto &point : m_lowPolyLogo.first()) + points << point; + QTest::newRow("QVariantList of points") << QVariant::fromValue(points); + } + { + QVector points; + for (const auto &point : m_lowPolyLogo.first()) + points << point.toPoint(); + QTest::newRow("vector of QPoint (integer points)") << QVariant::fromValue(points); + } + // Oddly, QPolygon is not supported, even though it's really QVector. + // We don't want to have a special case for it in QQuickPathPolyline::setPath(), + // but it could potentially be supported by fixing one of the QVariant conversions. +} + +void tst_QQuickShape::polylineDataTypes() +{ + QFETCH(QVariant, path); + + QScopedPointer window(createView()); + window->setSource(testFileUrl("polyline.qml")); + QQuickShape *shape = qobject_cast(window->rootObject()); + QVERIFY(shape); + shape->setProperty("path", path); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimimal platforms", Abort); + + QImage img = window->grabWindow(); + QVERIFY(!img.isNull()); + + QImage refImg(testFileUrl("polyline.png").toLocalFile()); + QVERIFY(!refImg.isNull()); + + QString errorMessage; + const QImage actualImg = img.convertToFormat(refImg.format()); + const bool res = QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage); + if (!res) { // For visual inspection purposes. + QTest::qWait(5000); + const QString &tempLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation); + actualImg.save(tempLocation + QLatin1String("/polyline.png")); + } + QVERIFY2(res, qPrintable(errorMessage)); + + QCOMPARE(shape->property("path").value>(), m_lowPolyLogo.first()); + // Verify that QML sees it as an array of points + int i = 0; + for (QPointF p : m_lowPolyLogo.first()) { + QMetaObject::invokeMethod(shape, "checkVertexAt", Q_ARG(QVariant, QVariant::fromValue(i++))); + QCOMPARE(shape->property("vertexBeingChecked").toPointF(), p); + } +} + QTEST_MAIN(tst_QQuickShape) #include "tst_qquickshape.moc" -- cgit v1.2.3 From 811b15bd161d12e5c85e093f9f492a0c4fa278d6 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 16 Aug 2019 11:18:38 +0200 Subject: PathMultiline: allow lists/vectors of polygons or point lists/vectors If a C++ model object can make a vector of vectors of points available directly, and it is bound to a PathMultiline's paths property to provide the view layer, it's a waste of time to convert it to a QVariantList of QVariantLists and back again. Changing the type of the property to QVariant instead of QVariantList enables an extensible set of supported types: all those that make sense. Fixes: QTBUG-77929 Change-Id: If749c2171173e7b9933fc9ecdf6d2741dc1c7500 Reviewed-by: Paolo Angelelli --- src/quick/util/qquickpath.cpp | 70 +++++----- src/quick/util/qquickpath_p.h | 6 +- tests/auto/quick/qquickshape/data/multiline.png | Bin 0 -> 1244 bytes tests/auto/quick/qquickshape/data/multiline.qml | 52 ++++++++ tests/auto/quick/qquickshape/tst_qquickshape.cpp | 160 +++++++++++++++++++++++ 5 files changed, 253 insertions(+), 35 deletions(-) create mode 100644 tests/auto/quick/qquickshape/data/multiline.png create mode 100644 tests/auto/quick/qquickshape/data/multiline.qml diff --git a/src/quick/util/qquickpath.cpp b/src/quick/util/qquickpath.cpp index 6d4e469e44..bebe9b2563 100644 --- a/src/quick/util/qquickpath.cpp +++ b/src/quick/util/qquickpath.cpp @@ -2532,48 +2532,54 @@ void QQuickPathPolyline::addToPath(QPainterPath &path, const QQuickPathData &/*d \qmlproperty list> QtQuick::PathMultiline::paths This property defines the vertices of the polylines. + + It can be a JS array of JS arrays of points constructed with \c Qt.point(), + a QList or QVector of QPolygonF, or QVector>. + If you are binding this to a custom property in some C++ object, + QVector or QVector> is the most + appropriate type to use. */ QQuickPathMultiline::QQuickPathMultiline(QObject *parent) : QQuickCurve(parent) { } -QVariantList QQuickPathMultiline::paths() const +QVariant QQuickPathMultiline::paths() const { - QVariantList res; - for (int j = 0; j < m_paths.length(); ++j) { - const QVector &path = m_paths.at(j); - QVariantList p; - for (int i = 0; i < path.length(); ++i) { - const QPointF &c = path.at(i); - p.append(QVariant::fromValue(c)); - } - res.append(p); - } - return res; -} - -void QQuickPathMultiline::setPaths(const QVariantList &paths) -{ - QVector> pathsList; - for (int j = 0; j < paths.length(); ++j) { - if (paths.at(j).type() != QVariant::List) - qWarning() << "QQuickPathMultiLine::setPaths: elements in argument not of type List"; - QVariantList path = paths.at(j).toList(); - QVector l; - for (int i = 0; i < path.length(); ++i) { - const QVariant &element = path.at(i); - const QVariant::Type elementType = element.type(); - if (elementType == QVariant::PointF || elementType == QVariant::Point) { - const QPointF c = element.toPointF(); - l.append(c); + return QVariant::fromValue(m_paths); +} + +void QQuickPathMultiline::setPaths(const QVariant &paths) +{ + if (paths.canConvert>()) { + const QVector pathPolygons = paths.value>(); + QVector> pathVectors; + for (const QPolygonF &p : pathPolygons) + pathVectors << p; + setPaths(pathVectors); + } else if (paths.canConvert>>()) { + setPaths(paths.value>>()); + } else if (paths.canConvert()) { + // This handles cases other than QVector or QVector>, such as + // QList>, QList>, QVariantList of QVector, + // QVariantList of QVariantList of QPointF, QVector> etc. + QVector> pathsList; + QVariantList vll = paths.value(); + for (const QVariant &v : vll) { + QVariantList vl = v.value(); + QVector l; + for (const QVariant &point : vl) { + if (point.canConvert()) + l.append(point.toPointF()); } + if (l.size() >= 2) + pathsList.append(l); } - if (l.size() >= 2) - pathsList.append(l); + setPaths(pathsList); + } else { + qWarning() << "PathMultiline: paths of type" << paths.type() << "not supported"; + setPaths(QVector>()); } - - setPaths(pathsList); } void QQuickPathMultiline::setPaths(const QVector> &paths) diff --git a/src/quick/util/qquickpath_p.h b/src/quick/util/qquickpath_p.h index e37a2e2dce..5987ae8f35 100644 --- a/src/quick/util/qquickpath_p.h +++ b/src/quick/util/qquickpath_p.h @@ -450,12 +450,12 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPathMultiline : public QQuickCurve { Q_OBJECT Q_PROPERTY(QPointF start READ start NOTIFY startChanged) - Q_PROPERTY(QVariantList paths READ paths WRITE setPaths NOTIFY pathsChanged) + Q_PROPERTY(QVariant paths READ paths WRITE setPaths NOTIFY pathsChanged) public: QQuickPathMultiline(QObject *parent=nullptr); - QVariantList paths() const; - void setPaths(const QVariantList &paths); + QVariant paths() const; + void setPaths(const QVariant &paths); void setPaths(const QVector> &paths); QPointF start() const; void addToPath(QPainterPath &path, const QQuickPathData &) override; diff --git a/tests/auto/quick/qquickshape/data/multiline.png b/tests/auto/quick/qquickshape/data/multiline.png new file mode 100644 index 0000000000..ae25d111df Binary files /dev/null and b/tests/auto/quick/qquickshape/data/multiline.png differ diff --git a/tests/auto/quick/qquickshape/data/multiline.qml b/tests/auto/quick/qquickshape/data/multiline.qml new file mode 100644 index 0000000000..ad07506972 --- /dev/null +++ b/tests/auto/quick/qquickshape/data/multiline.qml @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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$ +** +****************************************************************************/ + +import QtQuick 2.14 +import QtQuick.Shapes 1.14 + +Shape { + width: 200 + height: 150 + vendorExtensionsEnabled: false + objectName: "shape" + id: shape + property alias paths: multiline.paths + property point vertexBeingChecked; + + function checkVertexAt(i, j) { + vertexBeingChecked = multiline.paths[i][j] + } + + ShapePath { + strokeWidth: 4 + strokeColor: "green" + PathMultiline { + id: multiline + } + } +} diff --git a/tests/auto/quick/qquickshape/tst_qquickshape.cpp b/tests/auto/quick/qquickshape/tst_qquickshape.cpp index 69b65f0ec9..6bd8562823 100644 --- a/tests/auto/quick/qquickshape/tst_qquickshape.cpp +++ b/tests/auto/quick/qquickshape/tst_qquickshape.cpp @@ -62,6 +62,8 @@ private slots: void renderMultiline(); void polylineDataTypes_data(); void polylineDataTypes(); + void multilineDataTypes_data(); + void multilineDataTypes(); private: QVector m_lowPolyLogo; @@ -475,6 +477,164 @@ void tst_QQuickShape::polylineDataTypes() } } +void tst_QQuickShape::multilineDataTypes_data() +{ + QTest::addColumn("paths"); + + QTest::newRow("vector of polygons") << QVariant::fromValue(m_lowPolyLogo); + { + QVector> paths; + for (const auto &poly : m_lowPolyLogo) { + QVector points; + points << poly; + paths << points; + } + QTest::newRow("vector of point vectors") << QVariant::fromValue(paths); + } + { + QList> paths; + for (const auto &poly : m_lowPolyLogo) { + QVector points; + points << poly; + paths << points; + } + QTest::newRow("list of point vectors") << QVariant::fromValue(paths); + } + { + QList> paths; + for (const auto &poly : m_lowPolyLogo) { + QList points; + for (const auto &point : poly) + points << point; + paths << points; + } + QTest::newRow("list of point lists") << QVariant::fromValue(paths); + } + { + QVariantList paths; + for (const auto &poly : m_lowPolyLogo) { + QVector points; + points << poly; + paths << QVariant::fromValue(points); + } + QTest::newRow("QVariantList of point vectors") << QVariant::fromValue(paths); + } + { + QVariantList paths; + for (const auto &poly : m_lowPolyLogo) { + QList points; + for (const auto &point : poly) + points << point; + paths << QVariant::fromValue(points); + } + QTest::newRow("QVariantList of point lists") << QVariant::fromValue(paths); + } + { + QVariantList paths; + for (const auto &poly : m_lowPolyLogo) { + QVariantList points; + for (const auto &point : poly) + points << point; + paths << QVariant::fromValue(points); + } + QTest::newRow("QVariantList of QVariantLists") << QVariant::fromValue(paths); + } + /* These could be supported if QVariant knew how to convert lists and vectors of QPolygon to QPolygonF. + But they are omitted for now because we don't want to have special cases for them + in QQuickPathMultiline::setPaths(). Floating point is preferred for geometry in Qt Quick. + { + QList paths; + for (const auto &poly : m_lowPolyLogo) + paths << poly.toPolygon(); + QTest::newRow("list of QPolygon (integer points)") << QVariant::fromValue(paths); + } + { + QVector paths; + for (const auto &poly : m_lowPolyLogo) + paths << poly.toPolygon(); + QTest::newRow("vector of QPolygon (integer points)") << QVariant::fromValue(paths); + } + */ + { + QList> paths; + for (const auto &poly : m_lowPolyLogo) { + QList points; + for (const auto &point : poly) + points << point.toPoint(); + paths << points; + } + QTest::newRow("list of integer point lists") << QVariant::fromValue(paths); + } + { + QVector> paths; + for (const auto &poly : m_lowPolyLogo) { + QList points; + for (const auto &point : poly) + points << point.toPoint(); + paths << points; + } + QTest::newRow("vector of integer point lists") << QVariant::fromValue(paths); + } + { + QList> paths; + for (const auto &poly : m_lowPolyLogo) { + QVector points; + for (const auto &point : poly) + points << point.toPoint(); + paths << points; + } + QTest::newRow("list of integer point vectors") << QVariant::fromValue(paths); + } +} + +void tst_QQuickShape::multilineDataTypes() +{ + QFETCH(QVariant, paths); + + QScopedPointer window(createView()); + window->setSource(testFileUrl("multiline.qml")); + QQuickShape *shape = qobject_cast(window->rootObject()); + QVERIFY(shape); + shape->setProperty("paths", paths); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimimal platforms", Abort); + + QImage img = window->grabWindow(); + QVERIFY(!img.isNull()); + + QImage refImg(testFileUrl("multiline.png").toLocalFile()); + QVERIFY(!refImg.isNull()); + + QString errorMessage; + const QImage actualImg = img.convertToFormat(refImg.format()); + const bool res = QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage); + if (!res) { // For visual inspection purposes. + QTest::qWait(5000); + const QString &tempLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation); + actualImg.save(tempLocation + QLatin1String("/multiline.png")); + } + QVERIFY2(res, qPrintable(errorMessage)); + + QVector> pointVectors; + for (auto v : m_lowPolyLogo) + pointVectors << v; + QCOMPARE(shape->property("paths").value>>(), pointVectors); + // Verify that QML sees it as an array of arrays of points + int i = 0; + for (auto pv : m_lowPolyLogo) { + int j = 0; + for (QPointF p : pv) { + QMetaObject::invokeMethod(shape, "checkVertexAt", Q_ARG(QVariant, QVariant::fromValue(i)), Q_ARG(QVariant, QVariant::fromValue(j++))); + QCOMPARE(shape->property("vertexBeingChecked").toPointF(), p); + } + ++i; + } +} + QTEST_MAIN(tst_QQuickShape) #include "tst_qquickshape.moc" -- cgit v1.2.3 From 45b1a3f97953fac65c6aef8e46abad865a0d0bc3 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Fri, 30 Aug 2019 15:55:33 +0200 Subject: Allow semicolon after property declaration Most of the rules already had Semicolon at the end, however it was missing for UiScriptStatement, list properties and UiObjectInitializer. This change fixes the regression from 5.11.3 to 5.12.0, and keeps the behavior consistent. Fixes: QTBUG-77954 Change-Id: I45ef35fab399e3f971444b96d4a9ec6a99e29e09 Reviewed-by: Ulf Hermann --- src/qml/parser/qqmljs.g | 19 ++++++++++++------- .../qqmlecmascript/data/semicolonAfterProperty.qml | 10 ++++++++++ tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 11 +++++++++++ 3 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 tests/auto/qml/qqmlecmascript/data/semicolonAfterProperty.qml diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g index 6c9760e472..8ac7633ae0 100644 --- a/src/qml/parser/qqmljs.g +++ b/src/qml/parser/qqmljs.g @@ -1246,8 +1246,13 @@ UiObjectMember: T_DEFAULT T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlId sym(1).Node = node; } break; ./ +OptionalSemicolon: | Semicolon; +/. +/* we need OptionalSemicolon because UiScriptStatement might already parse the last semicolon + and then we would miss a semicolon (see tests/auto/quick/qquickvisualdatamodel/data/objectlist.qml)*/ + ./ -UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement; +UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon; /. case $rule_number: { AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3), sym(5).Statement); @@ -1259,7 +1264,7 @@ UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatemen } break; ./ -UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement; +UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon; /. case $rule_number: { AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4), sym(6).Statement); @@ -1273,7 +1278,7 @@ UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScr } break; ./ -UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement; +UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon; /. case $rule_number: { AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4), sym(6).Statement); @@ -1287,7 +1292,7 @@ UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScri } break; ./ -UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET; +UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET Semicolon; /. case $rule_number: { AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6)); @@ -1313,7 +1318,7 @@ UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T } break; ./ -UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET; +UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET Semicolon; /. case $rule_number: { AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(5).UiQualifiedId->finish(), stringRef(7)); @@ -1341,7 +1346,7 @@ UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlI } break; ./ -UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer; +UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer Semicolon; /. case $rule_number: { AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3)); @@ -1364,7 +1369,7 @@ UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatem } break; ./ -UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer; +UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer Semicolon; /. case $rule_number: { AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4)); diff --git a/tests/auto/qml/qqmlecmascript/data/semicolonAfterProperty.qml b/tests/auto/qml/qqmlecmascript/data/semicolonAfterProperty.qml new file mode 100644 index 0000000000..0a75ea6f36 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/semicolonAfterProperty.qml @@ -0,0 +1,10 @@ +import QtQml 2.0 + +QtObject { + property var field: { "key": "value"}; + property list mylist: [ + QtObject {id: a}, + QtObject {id: b} + ]; + property var object: QtObject {}; +} diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index b44fe9766c..269d90c891 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -374,6 +374,7 @@ private slots: void hugeRegexpQuantifiers(); void singletonTypeWrapperLookup(); void getThisObject(); + void semicolonAfterProperty(); private: // static void propertyVarWeakRefCallback(v8::Persistent object, void* parameter); @@ -9106,6 +9107,16 @@ void tst_qqmlecmascript::getThisObject() QTRY_COMPARE(qvariant_cast(test->property("self")), test.data()); } +// QTBUG-77954 +void tst_qqmlecmascript::semicolonAfterProperty() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("semicolonAfterProperty.qml")); + QVERIFY(component.isReady()); + QScopedPointer test(component.create()); + QVERIFY(!test.isNull()); +} + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" -- cgit v1.2.3 From e81ff5732f7884c5c1d9efb1f63ac7ad0dabbcb5 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 2 Sep 2019 22:28:43 +0200 Subject: PathMultiline: handle directly-bound QVector The autotest in 811b15bd161d12e5c85e093f9f492a0c4fa278d6 only tested what happens if the vector of polygons is passed via a QVariant to the PathMultiline paths property. But the intention (as documented) was to literally support an object with Q_PROPERTY(QVector paths ...) and binding that paths property to PathMultiline.paths. In that case it appears in QQuickPathMultiline::setPaths() as a QVariant, canConvert>() returns false, then canConvert() returns true. Nevertheless each variant in the QVariantList is a QPolygonF, as expected. So we need another check to detect this case. Also added a test specifically for that. Fixes: QTBUG-77929 Change-Id: I84d0a45326d5f007b8ba3cc9bb1fbccf0345d812 Reviewed-by: Paolo Angelelli --- src/quick/util/qquickpath.cpp | 20 +++--- .../qquickshape/data/multilineStronglyTyped.qml | 59 ++++++++++++++++++ tests/auto/quick/qquickshape/tst_qquickshape.cpp | 72 ++++++++++++++++++++++ 3 files changed, 144 insertions(+), 7 deletions(-) create mode 100644 tests/auto/quick/qquickshape/data/multilineStronglyTyped.qml diff --git a/src/quick/util/qquickpath.cpp b/src/quick/util/qquickpath.cpp index bebe9b2563..61319c388c 100644 --- a/src/quick/util/qquickpath.cpp +++ b/src/quick/util/qquickpath.cpp @@ -2566,14 +2566,20 @@ void QQuickPathMultiline::setPaths(const QVariant &paths) QVector> pathsList; QVariantList vll = paths.value(); for (const QVariant &v : vll) { - QVariantList vl = v.value(); - QVector l; - for (const QVariant &point : vl) { - if (point.canConvert()) - l.append(point.toPointF()); + // If we bind a QVector property directly, rather than via QVariant, + // it will come through as QJSValue that can be converted to QVariantList of QPolygonF. + if (v.canConvert()) { + pathsList.append(v.value()); + } else { + QVariantList vl = v.value(); + QVector l; + for (const QVariant &point : vl) { + if (point.canConvert()) + l.append(point.toPointF()); + } + if (l.size() >= 2) + pathsList.append(l); } - if (l.size() >= 2) - pathsList.append(l); } setPaths(pathsList); } else { diff --git a/tests/auto/quick/qquickshape/data/multilineStronglyTyped.qml b/tests/auto/quick/qquickshape/data/multilineStronglyTyped.qml new file mode 100644 index 0000000000..46d650e053 --- /dev/null +++ b/tests/auto/quick/qquickshape/data/multilineStronglyTyped.qml @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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$ +** +****************************************************************************/ + +import QtQuick 2.14 +import QtQuick.Shapes 1.14 +import Qt.test 1.0 + +Shape { + width: 200 + height: 150 + vendorExtensionsEnabled: false + objectName: "shape" + id: shape + property alias paths: multiline.paths + property point vertexBeingChecked; + + function checkVertexAt(i, j) { + vertexBeingChecked = multiline.paths[i][j] + } + + PolygonProvider { + id: provider + objectName: "provider" + } + + ShapePath { + strokeWidth: 4 + strokeColor: "green" + PathMultiline { + id: multiline + paths: provider.paths + } + } +} diff --git a/tests/auto/quick/qquickshape/tst_qquickshape.cpp b/tests/auto/quick/qquickshape/tst_qquickshape.cpp index 6bd8562823..851475e2cd 100644 --- a/tests/auto/quick/qquickshape/tst_qquickshape.cpp +++ b/tests/auto/quick/qquickshape/tst_qquickshape.cpp @@ -43,6 +43,28 @@ using namespace QQuickViewTestUtil; using namespace QQuickVisualTestUtil; +class PolygonProvider : public QObject +{ + Q_OBJECT + Q_PROPERTY(QVector paths READ paths WRITE setPaths NOTIFY pathsChanged) + +public: + QVector paths() const { return m_paths; } + void setPaths(QVector paths) + { + if (m_paths == paths) + return; + m_paths = paths; + emit pathsChanged(); + } + +signals: + void pathsChanged(); + +private: + QVector m_paths; +}; + class tst_QQuickShape : public QQmlDataTest { Q_OBJECT @@ -64,6 +86,7 @@ private slots: void polylineDataTypes(); void multilineDataTypes_data(); void multilineDataTypes(); + void multilineStronglyTyped(); private: QVector m_lowPolyLogo; @@ -82,6 +105,7 @@ tst_QQuickShape::tst_QQuickShape() qmlRegisterType(uri, 1, 0, "RadialGradient"); qmlRegisterType(uri, 1, 0, "ConicalGradient"); qmlRegisterType(uri, 1, 0, "PathPolyline"); + qmlRegisterType("Qt.test", 1, 0, "PolygonProvider"); m_lowPolyLogo << (QPolygonF() << QPointF(20, 0) << @@ -635,6 +659,54 @@ void tst_QQuickShape::multilineDataTypes() } } +void tst_QQuickShape::multilineStronglyTyped() +{ + QScopedPointer window(createView()); + window->setSource(testFileUrl("multilineStronglyTyped.qml")); + QQuickShape *shape = qobject_cast(window->rootObject()); + QVERIFY(shape); + PolygonProvider *provider = shape->findChild("provider"); + QVERIFY(provider); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + provider->setPaths(m_lowPolyLogo); + + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimimal platforms", Abort); + + QImage img = window->grabWindow(); + QVERIFY(!img.isNull()); + + QImage refImg(testFileUrl("multiline.png").toLocalFile()); + QVERIFY(!refImg.isNull()); + + QString errorMessage; + const QImage actualImg = img.convertToFormat(refImg.format()); + const bool res = QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage); + if (!res) { // For visual inspection purposes. + QTest::qWait(5000); + const QString &tempLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation); + actualImg.save(tempLocation + QLatin1String("/multilineStronglyTyped.png")); + } + QVERIFY2(res, qPrintable(errorMessage)); + + QVector> pointVectors; + for (auto v : m_lowPolyLogo) + pointVectors << v; + QCOMPARE(shape->property("paths").value>>(), pointVectors); + // Verify that QML sees it as an array of arrays of points + int i = 0; + for (auto pv : m_lowPolyLogo) { + int j = 0; + for (QPointF p : pv) { + QMetaObject::invokeMethod(shape, "checkVertexAt", Q_ARG(QVariant, QVariant::fromValue(i)), Q_ARG(QVariant, QVariant::fromValue(j++))); + QCOMPARE(shape->property("vertexBeingChecked").toPointF(), p); + } + ++i; + } +} + QTEST_MAIN(tst_QQuickShape) #include "tst_qquickshape.moc" -- cgit v1.2.3 From bdf0a46c289298f7378796d62ae5fb283e08657d Mon Sep 17 00:00:00 2001 From: Jeremy Katz Date: Thu, 29 Aug 2019 22:26:46 -0700 Subject: ColumnLayout and RowLayout documentation typo from left ro right => from left to right Change-Id: Id7386a89438f74573bdb4b43702eadabb6805e50 Reviewed-by: Leena Miettinen --- src/imports/layouts/qquicklinearlayout.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/imports/layouts/qquicklinearlayout.cpp b/src/imports/layouts/qquicklinearlayout.cpp index fa51ef1f2f..af7b1b7340 100644 --- a/src/imports/layouts/qquicklinearlayout.cpp +++ b/src/imports/layouts/qquicklinearlayout.cpp @@ -759,7 +759,7 @@ QQuickLinearLayout::QQuickLinearLayout(Qt::Orientation orientation, \since QtQuick.Layouts 1.1 This property holds the layout direction of the row layout - it controls whether items are laid - out from left ro right or right to left. If \c Qt.RightToLeft is specified, + out from left to right or right to left. If \c Qt.RightToLeft is specified, left-aligned items will be right-aligned and right-aligned items will be left-aligned. Possible values: @@ -776,7 +776,7 @@ QQuickLinearLayout::QQuickLinearLayout(Qt::Orientation orientation, \since QtQuick.Layouts 1.1 This property holds the layout direction of the column layout - it controls whether items are laid - out from left ro right or right to left. If \c Qt.RightToLeft is specified, + out from left to right or right to left. If \c Qt.RightToLeft is specified, left-aligned items will be right-aligned and right-aligned items will be left-aligned. Possible values: -- cgit v1.2.3