From 45448222fc2a24f848effb6ed16c8c5adfab776a Mon Sep 17 00:00:00 2001 From: Dmitry Shachnev Date: Wed, 18 Aug 2021 22:50:29 +0300 Subject: Include in Yarr.h to fix build with GCC 11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - (aka ) is needed for UINT_MAX macro constant. - is needed for std::numeric_limits. Without this fix, qtdeclarative failed to build on some platforms: In file included from jsruntime/qv4regexp_p.h:62, from jsruntime/qv4regexp.cpp:40: ../3rdparty/masm/yarr/Yarr.h:46:44: error: ‘numeric_limits’ is not a member of ‘std’ 46 | static const unsigned offsetNoMatch = std::numeric_limits::max(); | ^~~~~~~~~~~~~~ Change-Id: I7cc9f7bc6624a52c8659f09034ab16064da5fd2f Reviewed-by: Albert Astals Cid Reviewed-by: Ulf Hermann (cherry picked from commit db58b8518e157b765bf2e01e6382a9eed4751f27) Reviewed-by: Qt Cherry-pick Bot --- src/3rdparty/masm/yarr/Yarr.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/3rdparty/masm/yarr/Yarr.h b/src/3rdparty/masm/yarr/Yarr.h index ccf78f9880..2955ea7e72 100644 --- a/src/3rdparty/masm/yarr/Yarr.h +++ b/src/3rdparty/masm/yarr/Yarr.h @@ -28,6 +28,7 @@ #pragma once #include +#include #include "YarrErrorCode.h" namespace JSC { namespace Yarr { -- cgit v1.2.3 From e6d106db2284d7eb50ca040b454109f686adf59e Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 16 Aug 2021 15:02:40 +0200 Subject: QmlPreview: Protect QQmlPreviewFileLoader::load with another mutex We can concurrently load multiple files from different threads, but the loader can only handle one such request at a time. Fixes: QTBUG-95825 Change-Id: I2b94d55f2cf0da6e84dabc47df5699cc57b903a6 Reviewed-by: Maximilian Goldstein Reviewed-by: Knud Dollereder (cherry picked from commit a068fdc0b2cf7d4223d9ad15345fe9d345875936) Reviewed-by: Fabian Kosmale --- .../qmldbg_preview/qqmlpreviewfileengine.cpp | 8 ++++++++ .../qmldbg_preview/qqmlpreviewfileloader.cpp | 20 ++++++++++---------- .../qmldbg_preview/qqmlpreviewfileloader.h | 5 ++++- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileengine.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileengine.cpp index 620c1cf1ba..7b53402df9 100644 --- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileengine.cpp +++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileengine.cpp @@ -398,6 +398,14 @@ bool QQmlPreviewFileEngine::supportsExtension(Extension extension) const void QQmlPreviewFileEngine::load() const { + // We can get here from different threads on different instances of QQmlPreviewFileEngine. + // However, there is only one loader per QQmlPreviewFileEngineHandler and it is not thread-safe. + // Its content mutex doesn't help us here because we explicitly wait on it in load(), which + // causes it to be released. Therefore, lock the load mutex first. + // This doesn't cause any deadlocks because the only thread that wakes the loader on the content + // mutex never calls load(). It's the QML debug server thread that handles the debug protocol. + QMutexLocker loadLocker(m_loader->loadMutex()); + m_result = m_loader->load(m_absolute); switch (m_result) { case QQmlPreviewFileLoader::File: diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp index 72abba6154..f97dcfc767 100644 --- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp +++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp @@ -101,7 +101,7 @@ QQmlPreviewFileLoader::~QQmlPreviewFileLoader() { QQmlPreviewFileLoader::Result QQmlPreviewFileLoader::load(const QString &path) { - QMutexLocker locker(&m_mutex); + QMutexLocker locker(&m_contentMutex); m_path = path; auto fileIterator = m_fileCache.constFind(path); @@ -124,19 +124,19 @@ QQmlPreviewFileLoader::Result QQmlPreviewFileLoader::load(const QString &path) m_entries.clear(); m_contents.clear(); emit request(path); - m_waitCondition.wait(&m_mutex); + m_waitCondition.wait(&m_contentMutex); return m_result; } QByteArray QQmlPreviewFileLoader::contents() { - QMutexLocker locker(&m_mutex); + QMutexLocker locker(&m_contentMutex); return m_contents; } QStringList QQmlPreviewFileLoader::entries() { - QMutexLocker locker(&m_mutex); + QMutexLocker locker(&m_contentMutex); return m_entries; } @@ -144,20 +144,20 @@ void QQmlPreviewFileLoader::whitelist(const QUrl &url) { const QString path = QQmlFile::urlToLocalFileOrQrc(url); if (!path.isEmpty()) { - QMutexLocker locker(&m_mutex); + QMutexLocker locker(&m_contentMutex); m_blacklist.whitelist(path); } } bool QQmlPreviewFileLoader::isBlacklisted(const QString &path) { - QMutexLocker locker(&m_mutex); + QMutexLocker locker(&m_contentMutex); return m_blacklist.isBlacklisted(path); } void QQmlPreviewFileLoader::file(const QString &path, const QByteArray &contents) { - QMutexLocker locker(&m_mutex); + QMutexLocker locker(&m_contentMutex); m_blacklist.whitelist(path); m_fileCache[path] = contents; if (path == m_path) { @@ -169,7 +169,7 @@ void QQmlPreviewFileLoader::file(const QString &path, const QByteArray &contents void QQmlPreviewFileLoader::directory(const QString &path, const QStringList &entries) { - QMutexLocker locker(&m_mutex); + QMutexLocker locker(&m_contentMutex); m_blacklist.whitelist(path); m_directoryCache[path] = entries; if (path == m_path) { @@ -181,7 +181,7 @@ void QQmlPreviewFileLoader::directory(const QString &path, const QStringList &en void QQmlPreviewFileLoader::error(const QString &path) { - QMutexLocker locker(&m_mutex); + QMutexLocker locker(&m_contentMutex); m_blacklist.blacklist(path); if (path == m_path) { m_result = Fallback; @@ -191,7 +191,7 @@ void QQmlPreviewFileLoader::error(const QString &path) void QQmlPreviewFileLoader::clearCache() { - QMutexLocker locker(&m_mutex); + QMutexLocker locker(&m_contentMutex); m_fileCache.clear(); m_directoryCache.clear(); } diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.h b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.h index 9c337935e3..e66294cb06 100644 --- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.h +++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.h @@ -79,7 +79,9 @@ public: QQmlPreviewFileLoader(QQmlPreviewServiceImpl *service); ~QQmlPreviewFileLoader(); + QMutex *loadMutex() { return &m_loadMutex; } Result load(const QString &file); + QByteArray contents(); QStringList entries(); @@ -90,7 +92,8 @@ signals: void request(const QString &file); private: - QMutex m_mutex; + QMutex m_loadMutex; + QMutex m_contentMutex; QWaitCondition m_waitCondition; QThread m_thread; -- cgit v1.2.3 From 5a6d15d2ad7c8c9edd2b194d1ed78e45872c6d18 Mon Sep 17 00:00:00 2001 From: Jarkko Koivikko Date: Thu, 5 Aug 2021 10:21:07 +0300 Subject: qquicktextinput: Clear pre-edit text after input method reset The QPlatformInputContext::reset() function does not allow any further input method events to be called. Therefore, clearing the pre-edit text is the sole responsibility of the text input control. This change modifies the QQuickTextInputPrivate::resetInputMethod() function and calls QQuickTextInputPrivate::cancelPreedit() instead of QInputMethod::reset() directly. The cancelPreedit() function will send a QInputMethodEvent which clears the IM state (in addition of calling QInputMethod::reset() function). Also, rename the QQuickTextInputPrivate::resetInputMethod() function to cancelInput, since it does not call inputMethod()->reset() directly. Fixes: QTBUG-95461 Change-Id: I6ab3b9dbe71956af72656e2a25a05d79603b34ea Reviewed-by: Volker Hilsheimer Reviewed-by: Lars Knoll Reviewed-by: Inho Lee Reviewed-by: Eskil Abrahamsen Blomfeldt Reviewed-by: Jarkko Koivikko (cherry picked from commit b2103e33f490c96d0068d211c6f2d5b540ca407e) Reviewed-by: Qt Cherry-pick Bot --- src/quick/items/qquicktextinput.cpp | 12 +++++++----- src/quick/items/qquicktextinput_p_p.h | 2 +- tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp | 2 ++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index 498fe8ab84..8840d8f49b 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -2105,7 +2105,7 @@ void QQuickTextInput::undo() { Q_D(QQuickTextInput); if (!d->m_readOnly) { - d->resetInputMethod(); + d->cancelInput(); d->internalUndo(); d->finishChange(-1, true); } @@ -2121,7 +2121,7 @@ void QQuickTextInput::redo() { Q_D(QQuickTextInput); if (!d->m_readOnly) { - d->resetInputMethod(); + d->cancelInput(); d->internalRedo(); d->finishChange(); } @@ -2748,11 +2748,13 @@ void QQuickTextInputPrivate::init() m_inputControl = new QInputControl(QInputControl::LineEdit, q); } -void QQuickTextInputPrivate::resetInputMethod() +void QQuickTextInputPrivate::cancelInput() { +#if QT_CONFIG(im) Q_Q(QQuickTextInput); if (!m_readOnly && q->hasActiveFocus() && qGuiApp) - QGuiApplication::inputMethod()->reset(); + cancelPreedit(); +#endif // im } void QQuickTextInput::updateCursorRectangle(bool scroll) @@ -4695,7 +4697,7 @@ void QQuickTextInput::ensureVisible(int position) void QQuickTextInput::clear() { Q_D(QQuickTextInput); - d->resetInputMethod(); + d->cancelInput(); d->clear(); } diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h index 2f700e3f3e..d6eda42954 100644 --- a/src/quick/items/qquicktextinput_p_p.h +++ b/src/quick/items/qquicktextinput_p_p.h @@ -173,7 +173,7 @@ public: } void init(); - void resetInputMethod(); + void cancelInput(); void startCreatingCursor(); void ensureVisible(int position, int preeditCursor = 0, int preeditLength = 0); void updateHorizontalScroll(); diff --git a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp index 7c5c09055d..0ef1711fd6 100644 --- a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp +++ b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp @@ -5924,6 +5924,7 @@ void tst_qquicktextinput::clear() textInput->clear(); QVERIFY(textInput->text().isEmpty()); + QVERIFY2(textInput->preeditText().isEmpty(), "Pre-edit text must be empty after clear"); QCOMPARE(spy.count(), 3); @@ -5932,6 +5933,7 @@ void tst_qquicktextinput::clear() QVERIFY(!textInput->canUndo()); QCOMPARE(spy.count(), 4); QCOMPARE(textInput->text(), QString("I am Legend")); + QVERIFY2(textInput->preeditText().isEmpty(), "Pre-edit text must be empty after undo"); } void tst_qquicktextinput::backspaceSurrogatePairs() -- cgit v1.2.3 From 3c896d3a3c158f7d01340229d6d98b8e077b9f46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Tue, 17 Aug 2021 10:01:18 +0200 Subject: Fix regression in ListView/Flickable event delivery The regression was introduced with 2acb31641fc9c34d24ac29232cdfec The problem was that when we entered QQuickListViewPrivate::wantsPointerEvent(), the event was not localized to the QQuickFlickable when mouse filtering was done. Therefore, since the code assumed that the localPos was local to the Flickable, it always ended up assuming that the point was within the bounds of the header/footer. Fixes: QTBUG-89409 Change-Id: Ib595e61b7995241b58e3051da09139e1e1f13cba Reviewed-by: Shawn Rutledge (cherry picked from commit b2e4f09bfa2c42af562f6741c0a0246a53028f0a) --- src/quick/items/qquickflickable.cpp | 15 ++- .../qquicklistview/data/delegateWithMouseArea2.qml | 120 +++++++++++++++++++++ .../quick/qquicklistview/tst_qquicklistview.cpp | 91 ++++++++++++++++ 3 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 tests/auto/quick/qquicklistview/data/delegateWithMouseArea2.qml diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index edeadfdb2d..ea97183c88 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -2445,7 +2445,20 @@ bool QQuickFlickable::filterMouseEvent(QQuickItem *receiver, QMouseEvent *event) bool QQuickFlickable::childMouseEventFilter(QQuickItem *i, QEvent *e) { Q_D(QQuickFlickable); - if (!isVisible() || !isEnabled() || !isInteractive() || !d->wantsPointerEvent(e)) { + auto wantsPointerEvent_helper = [=]() { + bool wants = true; + if (e->type() >= QEvent::MouseButtonPress && e->type() <= QEvent::MouseMove) { + QMouseEvent *me = static_cast(e); + QPointF itemLocalPos = me->localPos(); + me->setLocalPos(mapFromItem(i, itemLocalPos)); + wants = d->wantsPointerEvent(e); + // re-localize event back to \a i before returning + me->setLocalPos(itemLocalPos); + } + return wants; + }; + + if (!isVisible() || !isEnabled() || !isInteractive() || !wantsPointerEvent_helper()) { d->cancelInteraction(); return QQuickItem::childMouseEventFilter(i, e); } diff --git a/tests/auto/quick/qquicklistview/data/delegateWithMouseArea2.qml b/tests/auto/quick/qquicklistview/data/delegateWithMouseArea2.qml new file mode 100644 index 0000000000..dee89ae4cd --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/delegateWithMouseArea2.qml @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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: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.15 + +Rectangle { + + width: 240 + height: 320 + color: "#ffffff" + + Component { + id: myDelegate + Rectangle { + id: wrapper + width: list.orientation == ListView.Vertical ? 240 : 20 + height: list.orientation == ListView.Vertical ? 20 : 240 + border.width: 1 + border.color: "black" + MouseArea { + anchors.fill: parent + } + Text { + text: index + ":" + (list.orientation == ListView.Vertical ? parent.y : parent.x).toFixed(0) + } + color: ListView.isCurrentItem ? "lightsteelblue" : "white" + } + } + + ListView { + id: list + objectName: "list" + focus: true + width: 240 + height: 200 + clip: true + model: 30 + headerPositioning: ListView.OverlayHeader + delegate: myDelegate + + header: Rectangle { + width: list.orientation == Qt.Vertical ? 240 : 30 + height: list.orientation == Qt.Vertical ? 30 : 240 + color: "green" + z: 11 + Text { + anchors.centerIn: parent + text: "header " + (list.orientation == ListView.Vertical ? parent.y : parent.x).toFixed(1) + } + } + } + + // debug + Rectangle { + color: "#40ff0000" + border.width: txt.x + border.color: "black" + radius: 5 + width: txt.implicitWidth + 50 + height: txt.implicitHeight + 2 * txt.x + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.left: parent.left + + Text { + id: txt + x: 3 + y: x + text: "header position: " + (list.orientation == ListView.Vertical ? list.headerItem.y : list.headerItem.x).toFixed(1) + + "\ncontent position: " + (list.orientation == ListView.Vertical ? list.contentY : list.contentX).toFixed(1) + } + } +} diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index a7aefbe432..d3deb513d0 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -299,6 +299,8 @@ private slots: void requiredObjectListModel(); void clickHeaderAndFooterWhenClip(); void animatedDelegate(); + void dragDelegateWithMouseArea(); + void dragDelegateWithMouseArea_data(); private: template void items(const QUrl &source); @@ -10109,6 +10111,95 @@ void tst_QQuickListView::animatedDelegate() } } +static void dragListView(QWindow *window, QPoint *startPos, const QPoint &delta) +{ + auto drag_helper = [&](QWindow *window, QPoint *startPos, const QPoint &d) { + QPoint pos = *startPos; + const int dragDistance = d.manhattanLength(); + const QPoint unitVector(qBound(-1, d.x(), 1), qBound(-1, d.y(), 1)); + for (int i = 0; i < dragDistance; ++i) { + QTest::mouseMove(window, pos); + pos += unitVector; + } + // Move to the final position + pos = *startPos + d; + QTest::mouseMove(window, pos); + *startPos = pos; + }; + + if (delta.manhattanLength() == 0) + return; + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + const QPoint unitVector(qBound(-1, delta.x(), 1), qBound(-1, delta.y(), 1)); + // go just beyond the drag theshold + drag_helper(window, startPos, unitVector * (dragThreshold + 1)); + drag_helper(window, startPos, unitVector); + + // next drag will actually scroll the listview + drag_helper(window, startPos, delta); +} + +void tst_QQuickListView::dragDelegateWithMouseArea() +{ + QFETCH(QQuickItemView::LayoutDirection, layoutDirection); + + QScopedPointer window(createView()); + QVERIFY(window); + window->setSource(testFileUrl("delegateWithMouseArea2.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + QQuickListView *listview = findItem(window->rootObject(), "list"); + QVERIFY(listview != nullptr); + + const bool horizontal = layoutDirection < QQuickItemView::VerticalTopToBottom; + listview->setOrientation(horizontal ? QQuickListView::Horizontal : QQuickListView::Vertical); + + if (horizontal) + listview->setLayoutDirection(static_cast(layoutDirection)); + else + listview->setVerticalLayoutDirection(static_cast(layoutDirection)); + + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); + + auto contentPosition = [&](QQuickListView *listview) { + return (listview->orientation() == QQuickListView::Horizontal ? listview->contentX(): listview->contentY()); + }; + + qreal expectedContentPosition = contentPosition(listview); + QPoint startPos = (QPointF(listview->width(), listview->height())/2).toPoint(); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, startPos, 200); + + QPoint dragDelta(0, -10); + + if (layoutDirection == QQuickItemView::RightToLeft || layoutDirection == QQuickItemView::VerticalBottomToTop) + dragDelta = -dragDelta; + expectedContentPosition -= dragDelta.y(); + if (horizontal) + dragDelta = dragDelta.transposed(); + + dragListView(window.data(), &startPos, dragDelta); + + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, startPos, 200); // Wait 200 ms before we release to avoid trigger a flick + + // wait for the "fixup" animation to finish + QVERIFY(QTest::qWaitFor([&]() + { return !listview->isMoving();} + )); + + QCOMPARE(contentPosition(listview), expectedContentPosition); +} + +void tst_QQuickListView::dragDelegateWithMouseArea_data() +{ + QTest::addColumn("layoutDirection"); + + for (int layDir = QQuickItemView::LeftToRight; layDir <= (int)QQuickItemView::VerticalBottomToTop; layDir++) { + const char *enumValueName = QMetaEnum::fromType().valueToKey(layDir); + QTest::newRow(enumValueName) << static_cast(layDir); + } +} + QTEST_MAIN(tst_QQuickListView) #include "tst_qquicklistview.moc" -- cgit v1.2.3 From e49737c15007b74b0c2decef8e1af2895d2fee89 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Fri, 20 Aug 2021 15:30:22 +0200 Subject: Canvas: Add a means to override the DPR used via an environment variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Overriding the DPR enables the system to not use as much memory and resources that a low-end device or mobile might have a limited amount of for rendering the Canvas item. In a situation where the user is aware of the consequences and impact of forcing the DPR to be different to the canvas window's DPR then this can be useful in those situations. By having the environment variable to override the DPR then it makes it possible for those needing this right away in all versions of Qt, so we add this now with a view to add API for this at a later date. Change-Id: Icafaa04a15678e2c7f24bc791026676f476a6ced Reviewed-by: Mitch Curtis Reviewed-by: Morten Johan Sørvig Reviewed-by: Shawn Rutledge (cherry picked from commit b0193908258f315a5736edcbc2a034d3194d42c9) Reviewed-by: Qt Cherry-pick Bot --- src/quick/items/context2d/qquickcontext2dtexture.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/quick/items/context2d/qquickcontext2dtexture.cpp b/src/quick/items/context2d/qquickcontext2dtexture.cpp index 69ed7e5a6d..4248c192a9 100644 --- a/src/quick/items/context2d/qquickcontext2dtexture.cpp +++ b/src/quick/items/context2d/qquickcontext2dtexture.cpp @@ -165,8 +165,15 @@ void QQuickContext2DTexture::setItem(QQuickCanvasItem* item) bool QQuickContext2DTexture::setCanvasWindow(const QRect& r) { - qreal canvasDevicePixelRatio = (m_item && m_item->window()) ? - m_item->window()->effectiveDevicePixelRatio() : qApp->devicePixelRatio(); + bool ok = false; + static qreal overriddenDevicePixelRatio = + !qEnvironmentVariableIsEmpty("QT_CANVAS_OVERRIDE_DEVICEPIXELRATIO") ? + qgetenv("QT_CANVAS_OVERRIDE_DEVICEPIXELRATIO").toFloat(&ok) : 0.0; + qreal canvasDevicePixelRatio = overriddenDevicePixelRatio; + if (overriddenDevicePixelRatio == 0.0) { + canvasDevicePixelRatio = (m_item && m_item->window()) ? + m_item->window()->effectiveDevicePixelRatio() : qApp->devicePixelRatio(); + } if (!qFuzzyCompare(m_canvasDevicePixelRatio, canvasDevicePixelRatio)) { qCDebug(lcCanvas, "%s device pixel ratio %.1lf -> %.1lf", (m_item->objectName().isEmpty() ? "Canvas" : qPrintable(m_item->objectName())), -- cgit v1.2.3 From 2774ecb191862071bd1cb2dea1266feff377e3bc Mon Sep 17 00:00:00 2001 From: Tarja Sundqvist Date: Tue, 7 Sep 2021 17:09:01 +0300 Subject: Bump version Change-Id: I75db8b7233e8b3eef1d847e16caa8ac0640342e6 --- .qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qmake.conf b/.qmake.conf index e46219506c..aa20cb26e7 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.15.6 +MODULE_VERSION = 5.15.7 -- cgit v1.2.3 From 383b70aba1e27adb3e836db6f41edd2c8b6275ef Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 14 Sep 2021 13:05:58 +0200 Subject: Ensure init of m_current_projection_matrix in single-clipped-item scene If there is only one item in the scene, based on QSGRenderNode, with clipping turned on, then we did not end up in render(Un)MergedBatch(), so the usual initialization was not done, and the custom item was effectively invisible. This is because of directly calling renderRenderNode() from renderBatches(), bypassing the other places where it would normally be done; so now we initialize it only in that case in renderBatches(). Fixes: QTBUG-95881 Change-Id: Ic306ae16690103ad65a2e2ccc2f58907577e5b1b Reviewed-by: Laszlo Agocs --- src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index e6c2c1b573..fae9f78ddf 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -4042,12 +4042,14 @@ void Renderer::renderBatches() if (Q_LIKELY(renderAlpha)) { for (int i=0; imerged) + if (b->merged) { renderMergedBatch(b); - else if (b->isRenderNode) + } else if (b->isRenderNode) { + m_current_projection_matrix = projectionMatrix(); renderRenderNode(b); - else + } else { renderUnmergedBatch(b); + } } } -- cgit v1.2.3 From 341604be545b0fe43b18f3822e9c9da918f5f675 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Wed, 15 Sep 2021 11:14:23 +0200 Subject: Doc: mention that clipping can affect performance and link to page Amends c1c01e21d1a745eccb17d61e10d7f8a4d54d3a43. Change-Id: Id47df551065a2ae245b4909225fba08f6c07d274 Reviewed-by: Fabian Kosmale Reviewed-by: Shawn Rutledge (cherry picked from commit 9ab38cb213da03545d2430a7aeda8ac942cecc5f) Reviewed-by: Qt Cherry-pick Bot --- src/quick/items/qquickitem.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index dfc3ece60d..2389a44437 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -3717,6 +3717,9 @@ QList QQuickItem::childItems() const If clipping is enabled, an item will clip its own painting, as well as the painting of its children, to its bounding rectangle. + + \note Clipping can affect rendering performance. See \l {Clipping} for more + information. */ /*! \property QQuickItem::clip -- cgit v1.2.3 From e70e2f7d98f7763463413bfd6d2f9300e48087b4 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Thu, 16 Sep 2021 14:43:00 +0200 Subject: Reinitialize shader data structure when effect changes Shaders might not all have the same number of uniforms and locations, so reinitialize the array when the effect changes. Change-Id: I16b4f6b865ebe7b74c2960a1e88b8f12b83ee2b3 Done-with: Matt Galloway Fixes: QTBUG-55204 Reviewed-by: Laszlo Agocs --- src/quick/items/qquickopenglshadereffectnode.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/quick/items/qquickopenglshadereffectnode.cpp b/src/quick/items/qquickopenglshadereffectnode.cpp index 7bbed42a6f..9222cabf49 100644 --- a/src/quick/items/qquickopenglshadereffectnode.cpp +++ b/src/quick/items/qquickopenglshadereffectnode.cpp @@ -120,10 +120,13 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri : QQuickShaderEffect::Error); } + if (newEffect != oldEffect) + m_initialized = false; + int textureProviderIndex = 0; if (!m_initialized) { for (int shaderType = 0; shaderType < QQuickOpenGLShaderEffectMaterialKey::ShaderTypeCount; ++shaderType) { - Q_ASSERT(m_uniformLocs[shaderType].isEmpty()); + m_uniformLocs[shaderType].clear(); m_uniformLocs[shaderType].reserve(material->uniforms[shaderType].size()); for (int i = 0; i < material->uniforms[shaderType].size(); ++i) { const UniformData &d = material->uniforms[shaderType].at(i); -- cgit v1.2.3 From 78490dce1fdcadb5fca5caa44b61e45963e4baf9 Mon Sep 17 00:00:00 2001 From: Alexander Akulich Date: Thu, 16 Sep 2021 20:03:23 +0300 Subject: tst_grabImage: Fix the cases were visually comparing invisible items TestCase item has 'visible: false' set by default, and the grabImage() gets the data from QWindow surface. Make the root item visible so the test can get some data and actually check something. Also check the color of some grabbed pixels to see if we're working with the blank window background (before the root item 'visible' changed to 'true') or with the target item (after the fix). Change-Id: I107799a7442a62d44786003179e4595694c651a7 Reviewed-by: Shawn Rutledge Reviewed-by: Mitch Curtis (cherry picked from commit aed93ada4e58db8f1c36d7ed2c1074a514caf45a) Reviewed-by: Qt Cherry-pick Bot --- tests/auto/qmltest/selftests/tst_grabImage.qml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/auto/qmltest/selftests/tst_grabImage.qml b/tests/auto/qmltest/selftests/tst_grabImage.qml index 7ce7e93a07..714bc07f27 100644 --- a/tests/auto/qmltest/selftests/tst_grabImage.qml +++ b/tests/auto/qmltest/selftests/tst_grabImage.qml @@ -34,6 +34,7 @@ TestCase { id: testCase name: "tst_grabImage" when: windowShown + visible: true function test_equals() { var rect = createTemporaryQmlObject("import QtQuick 2.0; Rectangle { color: 'red'; width: 10; height: 10; }", testCase); @@ -47,6 +48,8 @@ TestCase { // Don't change anything... newImage = grabImage(rect); try { + // Check that we actually grabbed something + compare(newImage.pixel(0, 0), "#ff0000") compare(newImage.size, oldImage.size); verify(newImage.equals(oldImage)); } catch (ex) { @@ -86,6 +89,8 @@ TestCase { try { verify(grabbedImage2.equals(grabbedImage)) + // Check that we actually grabbed, saved, and loaded something + compare(grabbedImage2.pixel(0, 0), "#ff0000") } catch (ex) { grabbedImage2.save("tst_grabImage_test_save2.png") throw ex; -- cgit v1.2.3 From 657ce3c37e2aafd35ae3fba408620177f8bc0a1b Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Thu, 8 Jul 2021 22:47:07 +0200 Subject: doc: Remove bogus PinchHandler.minimumTouchPoints prop; improve actual PinchHandler.minimumTouchPoints was probably just an early idea for the name, because MultiPointTouchArea has it. Anyway it's now honoring the inherited minimum/maximumPointCount properties from MultiPointHandler. Change-Id: I6408da9dfe1d31a38da2777efa2c5d79ad17390f Reviewed-by: Fabian Kosmale (cherry picked from commit a04d98787dc5c816569a6eecce695a8d80257c05) Reviewed-by: Qt Cherry-pick Bot --- src/quick/handlers/qquickpinchhandler.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/quick/handlers/qquickpinchhandler.cpp b/src/quick/handlers/qquickpinchhandler.cpp index 13325f59c5..aebf9fc63e 100644 --- a/src/quick/handlers/qquickpinchhandler.cpp +++ b/src/quick/handlers/qquickpinchhandler.cpp @@ -85,7 +85,14 @@ Q_LOGGING_CATEGORY(lcPinchHandler, "qt.quick.handler.pinch") \image touchpoints-pinchhandler.png - \sa PinchArea + \note The pinch begins when the number of fingers pressed is between + \l {MultiPointHandler::minimumPointCount}{minimumPointCount} and + \l {MultiPointHandler::maximumPointCount}{maximumPointCount}, inclusive. + Until then, PinchHandler tracks the positions of any pressed fingers, + but if it's a disallowed number, it does not scale or rotate + its \l target, and the \l active property remains \c false. + + \sa PinchArea, QPointerEvent::pointCount() */ QQuickPinchHandler::QQuickPinchHandler(QQuickItem *parent) @@ -248,20 +255,13 @@ bool QQuickPinchHandler::wantsPointerEvent(QQuickPointerEvent *event) If \c enabled is true, vertical dragging is allowed. */ -/*! - \qmlproperty int QtQuick::PinchHandler::minimumTouchPoints - - The pinch begins when this number of fingers are pressed. - Until then, PinchHandler tracks the positions of any pressed fingers, - but if it's an insufficient number, it does not scale or rotate - its \l target, and the \l active property will remain false. -*/ - /*! \qmlproperty bool QtQuick::PinchHandler::active - This property is true when all the constraints (epecially \l minimumTouchPoints) - are satisfied and the \l target, if any, is being manipulated. + This property is \c true when all the constraints (epecially + \l {MultiPointHandler::minimumPointCount}{minimumPointCount} and + \l {MultiPointHandler::maximumPointCount}{maximumPointCount}) are satisfied + and the \l target, if any, is being manipulated. */ void QQuickPinchHandler::onActiveChanged() -- cgit v1.2.3 From bcce8187542d45b8986bd53cda3827d46badb82d Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 27 Sep 2021 11:00:20 +0200 Subject: Fix documentation on JavaScript imports Actually export the functions we use, clarify that import and .import are different, and discourage .import. Fixes: QTBUG-96902 Change-Id: I2471d876c83da3d2110add6005d54311d9261566 Reviewed-by: Maximilian Goldstein (cherry picked from commit 29946505a35f9f52ddc4f3e09e40c52efefad93d) Reviewed-by: Qt Cherry-pick Bot --- .../qml/integrating-javascript/includejs/script.mjs | 3 ++- src/qml/doc/src/javascript/imports.qdoc | 13 +++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/qml/doc/snippets/qml/integrating-javascript/includejs/script.mjs b/src/qml/doc/snippets/qml/integrating-javascript/includejs/script.mjs index 86c3e078c8..1326b8c87a 100644 --- a/src/qml/doc/snippets/qml/integrating-javascript/includejs/script.mjs +++ b/src/qml/doc/snippets/qml/integrating-javascript/includejs/script.mjs @@ -50,8 +50,9 @@ //![0] // script.mjs import { factorial } from "factorial.mjs" +export { factorial } -function showCalculations(value) { +export function showCalculations(value) { console.log( "Call factorial() from script.js:", factorial(value)); diff --git a/src/qml/doc/src/javascript/imports.qdoc b/src/qml/doc/src/javascript/imports.qdoc index 9227f0e604..8d49c02f62 100644 --- a/src/qml/doc/src/javascript/imports.qdoc +++ b/src/qml/doc/src/javascript/imports.qdoc @@ -95,17 +95,18 @@ or modules). A JavaScript resource may import another in the following fashion: \code -.import "filename.js" as Qualifier +import * as MathFunctions from "factorial.mjs"; \endcode -For example: +Or: \code -import * as MathFunctions from "factorial.mjs"; +.import "filename.js" as Qualifier \endcode -The latter is standard ECMAScript syntax for importing ECMAScript modules, and +The former is standard ECMAScript syntax for importing ECMAScript modules, and only works from within ECMAScript modules as denoted by the \c mjs file -extension. The former is an extension to JavaScript provided by the \c QML -engine and will work also with non-modules. +extension. The latter is an extension to JavaScript provided by the \c QML +engine and will work also with non-modules. As an extension superseded by the +ECMAScript standard, its usage is discouraged. When a JavaScript file is imported this way, it is imported with a qualifier. The functions in that file are then accessible from the importing script via the -- cgit v1.2.3 From dbb123217e26e1e099371cd7e28fb4999059f31b Mon Sep 17 00:00:00 2001 From: Aleix Pol Date: Tue, 21 Sep 2021 00:10:26 +0200 Subject: QQuickLoader: Do not incubate if the source arrives after setActive(false) Otherwise we end up in the crazy place of active being false but item being non-null and forces us to workaround within the apps. Change-Id: I88c27c4b00ccec8b8e0c05a8e10b44fcabfc2e30 Reviewed-by: Ulf Hermann (cherry picked from commit e78c068700fa74ab3aca6a23ab2450563b1c3a5c) Reviewed-by: Qt Cherry-pick Bot --- src/quick/items/qquickloader.cpp | 3 +++ .../qquickloader/data/loader-async-race-rect.qml | 10 ++++++++++ .../quick/qquickloader/data/loader-async-race.qml | 14 ++++++++++++++ tests/auto/quick/qquickloader/tst_qquickloader.cpp | 19 +++++++++++++++++++ 4 files changed, 46 insertions(+) create mode 100644 tests/auto/quick/qquickloader/data/loader-async-race-rect.qml create mode 100644 tests/auto/quick/qquickloader/data/loader-async-race.qml diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp index d2f083e295..88f8af81d2 100644 --- a/src/quick/items/qquickloader.cpp +++ b/src/quick/items/qquickloader.cpp @@ -737,6 +737,9 @@ void QQuickLoaderPrivate::_q_sourceLoaded() return; } + if (!active) + return; + QQmlContext *creationContext = component->creationContext(); if (!creationContext) creationContext = qmlContext(q); itemContext = new QQmlContext(creationContext); diff --git a/tests/auto/quick/qquickloader/data/loader-async-race-rect.qml b/tests/auto/quick/qquickloader/data/loader-async-race-rect.qml new file mode 100644 index 0000000000..a56dcea5ad --- /dev/null +++ b/tests/auto/quick/qquickloader/data/loader-async-race-rect.qml @@ -0,0 +1,10 @@ +import QtQuick 2.15 + +Rectangle { + anchors.fill: parent + color: "blue" + Item { + Item { + } + } +} diff --git a/tests/auto/quick/qquickloader/data/loader-async-race.qml b/tests/auto/quick/qquickloader/data/loader-async-race.qml new file mode 100644 index 0000000000..8ba625c5c1 --- /dev/null +++ b/tests/auto/quick/qquickloader/data/loader-async-race.qml @@ -0,0 +1,14 @@ +import QtQuick 2.15 + +Item { + id: root + Component.onCompleted: { + myloader.active = false + } + Loader { + id: myloader + anchors.fill: parent + asynchronous: true + source: "loader-async-race-rect.qml" + } +} diff --git a/tests/auto/quick/qquickloader/tst_qquickloader.cpp b/tests/auto/quick/qquickloader/tst_qquickloader.cpp index 0f6c811adb..dddacbaa0b 100644 --- a/tests/auto/quick/qquickloader/tst_qquickloader.cpp +++ b/tests/auto/quick/qquickloader/tst_qquickloader.cpp @@ -132,6 +132,7 @@ private slots: void statusChangeOnlyEmittedOnce(); void setSourceAndCheckStatus(); + void asyncLoaderRace(); }; Q_DECLARE_METATYPE(QList) @@ -1496,6 +1497,24 @@ void tst_QQuickLoader::setSourceAndCheckStatus() QCOMPARE(loader->status(), QQuickLoader::Null); } +void tst_QQuickLoader::asyncLoaderRace() +{ + QQmlApplicationEngine engine; + auto url = testFileUrl("loader-async-race.qml"); + engine.load(url); + auto root = engine.rootObjects().at(0); + QVERIFY(root); + + QQuickLoader *loader = root->findChild(); + QCOMPARE(loader->active(), false); + QCOMPARE(loader->status(), QQuickLoader::Null); + QCOMPARE(loader->item(), nullptr); + + QSignalSpy spy(loader, &QQuickLoader::itemChanged); + QVERIFY(!spy.wait(100)); + QCOMPARE(loader->item(), nullptr); +} + QTEST_MAIN(tst_QQuickLoader) #include "tst_qquickloader.moc" -- cgit v1.2.3 From 4cf8b6732a627cc73d22c95bd080dba447afb2e3 Mon Sep 17 00:00:00 2001 From: Joni Poikelin Date: Fri, 16 Apr 2021 15:24:29 +0300 Subject: Fix ListView.isCurrentItem when used with DelegateModel Fixes: QTBUG-86744 Change-Id: I7287b39afc8f84e336aa46739b534e33e4212ea7 Reviewed-by: Shawn Rutledge (cherry picked from commit d9f9d773e92940786f159897623618f3bf6bcf0f) --- src/quick/items/qquickitemview.cpp | 2 ++ tests/auto/quick/qquicklistview/data/qtbug86744.qml | 21 +++++++++++++++++++++ .../quick/qquicklistview/tst_qquicklistview.cpp | 15 +++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 tests/auto/quick/qquicklistview/data/qtbug86744.qml diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 3999109e47..80abd581d1 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -2402,6 +2402,8 @@ void QQuickItemView::createdItem(int index, QObject* object) d->repositionPackageItemAt(item, index); else if (index == d->currentIndex) d->updateCurrent(index); + } else if (index == d->currentIndex) { + d->updateCurrent(index); } } diff --git a/tests/auto/quick/qquicklistview/data/qtbug86744.qml b/tests/auto/quick/qquicklistview/data/qtbug86744.qml new file mode 100644 index 0000000000..6dc82d57eb --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/qtbug86744.qml @@ -0,0 +1,21 @@ +import QtQuick 2.15 +import QtQml.Models 2.15 + +Item { + height: 200 + width: 100 + DelegateModel { + id: dm + model: 2 + delegate: Item { + width: 100; height: 20 + property bool isCurrent: ListView.isCurrentItem + } + } + ListView { + objectName: "listView" + model: dm + currentIndex: 1 + anchors.fill: parent + } +} diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index d3deb513d0..df329f8318 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -301,6 +301,7 @@ private slots: void animatedDelegate(); void dragDelegateWithMouseArea(); void dragDelegateWithMouseArea_data(); + void isCurrentItem_DelegateModel(); private: template void items(const QUrl &source); @@ -10200,6 +10201,20 @@ void tst_QQuickListView::dragDelegateWithMouseArea_data() } } +void tst_QQuickListView::isCurrentItem_DelegateModel() +{ + QScopedPointer window(createView()); + window->setSource(testFileUrl("qtbug86744.qml")); + window->resize(640, 480); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + QQuickListView* listView = window->rootObject()->findChild("listView"); + QVERIFY(listView); + QVariant value = listView->itemAtIndex(1)->property("isCurrent"); + QVERIFY(value.toBool() == true); +} + QTEST_MAIN(tst_QQuickListView) #include "tst_qquicklistview.moc" -- cgit v1.2.3 From 198953cf139395b33a200fad978ef160191a0d78 Mon Sep 17 00:00:00 2001 From: Ivan Tkachenko Date: Mon, 27 Sep 2021 21:13:26 +0300 Subject: Doc: QQmlContext: make it more readable 9001 & 42 are much more visually distinctive than 12 & 15 which - if flipped in a right way - may even look identical. Change-Id: I63c6ad53e8be80c5bbc3856a964bbf31bd30a031 Reviewed-by: Ulf Hermann (cherry picked from commit 3262e0393da28e7344dec46b6a3baaa37ee3f5e4) Reviewed-by: Qt Cherry-pick Bot --- src/qml/qml/qqmlcontext.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp index e449208be3..8e4762e486 100644 --- a/src/qml/qml/qqmlcontext.cpp +++ b/src/qml/qml/qqmlcontext.cpp @@ -82,11 +82,11 @@ QQmlContextPrivate::QQmlContextPrivate() context->setContextProperty("myModel", &modelData); QQmlComponent component(&engine); - component.setData("import QtQuick 2.0\nListView { model: myModel }", QUrl()); + component.setData("import QtQuick 2.0; ListView { model: myModel }", QUrl()); QObject *window = component.create(context); \endcode - Note it is the responsibility of the creator to delete any QQmlContext it + \note It is the responsibility of the creator to delete any QQmlContext it constructs. If the \c context object in the example is no longer needed when the \c window component instance is destroyed, the \c context must be destroyed explicitly. The simplest way to ensure this is to set \c window as the parent of \c context. @@ -102,10 +102,10 @@ QQmlContextPrivate::QQmlContextPrivate() object. \code - class MyDataSet : ... { - ... + class MyDataSet : public QObject { + // ... Q_PROPERTY(QAbstractItemModel *myModel READ model NOTIFY modelChanged) - ... + // ... }; MyDataSet myDataSet; @@ -114,7 +114,7 @@ QQmlContextPrivate::QQmlContextPrivate() context->setContextObject(&myDataSet); QQmlComponent component(&engine); - component.setData("import QtQuick 2.0\nListView { model: myModel }", QUrl()); + component.setData("import QtQuick 2.0; ListView { model: myModel }", QUrl()); component.create(context); \endcode @@ -138,10 +138,10 @@ QQmlContextPrivate::QQmlContextPrivate() QQmlContext *context1 = new QQmlContext(engine.rootContext()); QQmlContext *context2 = new QQmlContext(context1); - context1->setContextProperty("a", 12); - context1->setContextProperty("b", 12); + context1->setContextProperty("a", 9001); + context1->setContextProperty("b", 9001); - context2->setContextProperty("b", 15); + context2->setContextProperty("b", 42); \endcode While QML objects instantiated in a context are not strictly owned by that -- cgit v1.2.3 From 5c72d47df884cf4b3fb5aa8de2f6dd56c5c46ab3 Mon Sep 17 00:00:00 2001 From: Ivan Tkachenko Date: Thu, 30 Sep 2021 14:01:10 +0300 Subject: Doc: Fix QtQuick::Keys::forwardTo generic list type Change-Id: I805ebc64c32ccc5c3f5612c6074610f6de04b40a Reviewed-by: Mitch Curtis (cherry picked from commit 1155ed6f2fc3da35faed85cd4c12a2f2e710c618) Reviewed-by: Qt Cherry-pick Bot --- src/quick/items/qquickitem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 2389a44437..5454a8a69c 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -905,7 +905,7 @@ bool QQuickKeysAttached::isConnected(const char *signalName) const */ /*! - \qmlproperty list QtQuick::Keys::forwardTo + \qmlproperty list QtQuick::Keys::forwardTo This property provides a way to forward key presses, key releases, and keyboard input coming from input methods to other items. This can be useful when you want -- cgit v1.2.3 From 8892a91389816cfbb0b1cbe6f7fa4d2a8ce4314b Mon Sep 17 00:00:00 2001 From: Ivan Tkachenko Date: Thu, 30 Sep 2021 14:13:05 +0300 Subject: Doc: Replace return `0` with nullptr Using zero as a pointer value is a legacy from the times before nullptr got standardized. Change-Id: I53d47eaa449a35eadc11d531e6965666c66a6be9 Reviewed-by: Paul Wicking (cherry picked from commit ca74ce8c7db4ceaeefd2aa66b58052a73488303f) Reviewed-by: Qt Cherry-pick Bot --- src/qml/qml/qqmlcontext.cpp | 6 +++--- src/qml/qml/qqmlexpression.cpp | 4 ++-- src/qml/qml/qqmlfileselector.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp index 8e4762e486..09d720da91 100644 --- a/src/qml/qml/qqmlcontext.cpp +++ b/src/qml/qml/qqmlcontext.cpp @@ -235,7 +235,7 @@ bool QQmlContext::isValid() const } /*! - Return the context's QQmlEngine, or 0 if the context has no QQmlEngine or the + Return the context's QQmlEngine, or \nullptr if the context has no QQmlEngine or the QQmlEngine was destroyed. */ QQmlEngine *QQmlContext::engine() const @@ -245,7 +245,7 @@ QQmlEngine *QQmlContext::engine() const } /*! - Return the context's parent QQmlContext, or 0 if this context has no + Return the context's parent QQmlContext, or \nullptr if this context has no parent or if the parent has been destroyed. */ QQmlContext *QQmlContext::parentContext() const @@ -255,7 +255,7 @@ QQmlContext *QQmlContext::parentContext() const } /*! - Return the context object, or 0 if there is no context object. + Return the context object, or \nullptr if there is no context object. */ QObject *QQmlContext::contextObject() const { diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp index 6acbd53557..37b6ad8c7e 100644 --- a/src/qml/qml/qqmlexpression.cpp +++ b/src/qml/qml/qqmlexpression.cpp @@ -204,7 +204,7 @@ QQmlExpression::~QQmlExpression() } /*! - Returns the QQmlEngine this expression is associated with, or 0 if there + Returns the QQmlEngine this expression is associated with, or \nullptr if there is no association or the QQmlEngine has been destroyed. */ QQmlEngine *QQmlExpression::engine() const @@ -214,7 +214,7 @@ QQmlEngine *QQmlExpression::engine() const } /*! - Returns the QQmlContext this expression is associated with, or 0 if there + Returns the QQmlContext this expression is associated with, or \nullptr if there is no association or the QQmlContext has been destroyed. */ QQmlContext *QQmlExpression::context() const diff --git a/src/qml/qml/qqmlfileselector.cpp b/src/qml/qml/qqmlfileselector.cpp index 674c08808f..f763d3669e 100644 --- a/src/qml/qml/qqmlfileselector.cpp +++ b/src/qml/qml/qqmlfileselector.cpp @@ -148,7 +148,7 @@ QQmlFileSelectorPrivate::~QQmlFileSelectorPrivate() /*! Sets the QFileSelector instance for use by the QQmlFileSelector to \a selector. QQmlFileSelector does not take ownership of the new QFileSelector. To reset QQmlFileSelector - to use its internal QFileSelector instance, call setSelector(0). + to use its internal QFileSelector instance, call setSelector(\nullptr). */ void QQmlFileSelector::setSelector(QFileSelector *selector) -- cgit v1.2.3 From 23b2fe7f06506c6c9975c003d3d3b3ba7b980f2d Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 19 Aug 2021 12:49:43 +0200 Subject: Document that clearComponentCache() does not clear existing objects Task-number: QTBUG-95788 Change-Id: I547ec38676d7e6f9b25fea79f58b94eacb135a5f Reviewed-by: Fabian Kosmale Reviewed-by: Paul Wicking (cherry picked from commit ae33c2da3ec33c2280167c0202aab6cd5d168b82) Reviewed-by: Qt Cherry-pick Bot --- src/qml/qml/qqmlengine.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 663c70fcb9..25f1e37fad 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -1063,6 +1063,16 @@ QQmlEngine::~QQmlEngine() Once the component cache has been cleared, components must be loaded before any new objects can be created. + \note Any existing objects created from QML components retain their types, + even if you clear the component cache. This includes singleton objects. If you + create more objects from the same QML code after clearing the cache, the new + objects will be of different types than the old ones. Assigning such a new + object to a property of its declared type belonging to an object created + before clearing the cache won't work. + + As a general rule of thumb, make sure that no objects created from QML + components are alive when you clear the component cache. + \sa trimComponentCache() */ void QQmlEngine::clearComponentCache() -- cgit v1.2.3 From 0e5cb85a1021815c1a3d38a67e936d90b59ddf45 Mon Sep 17 00:00:00 2001 From: Jarkko Koivikko Date: Tue, 14 Sep 2021 15:25:32 +0300 Subject: SaveableUnitPointer::saveToDisk restores flags incorrectly at cleanup SaveableUnitPointer::saveToDisk function uses XOR to restore flags, which causes the existing flags to be reset instead of restored. This can have major side effects, such as deallocation of StaticData units from static data cache (which should never be freed). Fixes: QTBUG-96275 Change-Id: I09c06f2854fe07a12a2d97290a3e39604a25fd9a Reviewed-by: Fabian Kosmale Reviewed-by: Andrei Golubev Reviewed-by: Jarkko Koivikko (cherry picked from commit 0645cf8e30e2311cc3d90cc2cb7abc7a27e91624) --- src/qml/common/qv4compileddata_p.h | 3 ++- tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/qml/common/qv4compileddata_p.h b/src/qml/common/qv4compileddata_p.h index 381a5735d3..231cd16d68 100644 --- a/src/qml/common/qv4compileddata_p.h +++ b/src/qml/common/qv4compileddata_p.h @@ -1330,7 +1330,8 @@ public: template bool saveToDisk(const std::function &writer) const { - auto cleanup = qScopeGuard([this]() { mutableFlags() ^= temporaryFlags; }); + const quint32_le oldFlags = mutableFlags(); + auto cleanup = qScopeGuard([this, oldFlags]() { mutableFlags() = oldFlags; }); mutableFlags() |= temporaryFlags; return writer(data(), size()); } diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp index 3810f505b3..65137c65a2 100644 --- a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp +++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include "../../shared/util.h" @@ -78,6 +79,8 @@ private slots: void parameterAdjustment(); void inlineComponent(); void posthocRequired(); + + void saveableUnitPointer(); }; // A wrapper around QQmlComponent to ensure the temporary reference counts @@ -713,6 +716,18 @@ void tst_qmlcachegen::posthocRequired() QVERIFY(component.errorString().contains(QStringLiteral("Required property x was not initialized"))); } +void tst_qmlcachegen::saveableUnitPointer() +{ + QV4::CompiledData::Unit unit; + unit.flags = QV4::CompiledData::Unit::StaticData | QV4::CompiledData::Unit::IsJavascript; + const auto flags = unit.flags; + + QV4::CompiledData::SaveableUnitPointer pointer(&unit); + + QVERIFY(pointer.saveToDisk([](const char *, quint32) { return true; })); + QCOMPARE(unit.flags, flags); +} + QTEST_GUILESS_MAIN(tst_qmlcachegen) #include "tst_qmlcachegen.moc" -- cgit v1.2.3 From 9a9df880cf78580c35f9ec31b3f522c4fe045e9f Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 4 Oct 2021 19:12:03 +0200 Subject: Stop using QHash::unite() in storage model manual test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was deprecated in qtbase 9c124b1b0a3730978699b8a6420308b5e5ab4e4e and removed in Qt 6. Change-Id: I0039bca92d005fc6533106662fc655ae7f76cc0b Reviewed-by: Mårten Nordheim (cherry picked from commit 87b80813d2b944479a589e2308f0846eb0e205f3) Reviewed-by: Qt Cherry-pick Bot --- .../manual/tableview/storagemodel/storagemodel.cpp | 25 ++++++++++++---------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/tests/manual/tableview/storagemodel/storagemodel.cpp b/tests/manual/tableview/storagemodel/storagemodel.cpp index b43454b249..f0394db6b8 100644 --- a/tests/manual/tableview/storagemodel/storagemodel.cpp +++ b/tests/manual/tableview/storagemodel/storagemodel.cpp @@ -64,17 +64,20 @@ StorageModel::StorageModel(QObject *parent) : } QHash StorageModel::roleNames() const { - static auto roles = QHash { - { int(Role::Type), "type" }, - { int(Role::Heading), "heading" }, - { int(Role::Value), "value" }, - { int(Role::ValueMax), "valueMax" }, - { int(Role::ValueDisplay), "valueDisplay" }, - { int(Role::ValueMaxDisplay), "valueMaxDisplay" }, - { Qt::CheckStateRole, "checkState" }, - }; - static auto ret = roles.unite(QAbstractTableModel::roleNames());; - return ret; + static auto roles = [this]() { + auto roles = QHash { + { int(Role::Type), "type" }, + { int(Role::Heading), "heading" }, + { int(Role::Value), "value" }, + { int(Role::ValueMax), "valueMax" }, + { int(Role::ValueDisplay), "valueDisplay" }, + { int(Role::ValueMaxDisplay), "valueMaxDisplay" }, + { Qt::CheckStateRole, "checkState" } + }; + roles.insert(QAbstractTableModel::roleNames()); + return roles; + }(); + return roles; } void StorageModel::refresh() -- cgit v1.2.3 From 4757cac470edbeaeaceca4e63075d9f1139f546b Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 12 Oct 2021 13:13:01 +0200 Subject: Fix distorted text with subpixel matrix translation We would pixel-align native text *before* applying the model-view matrix, which would cause GL_NEAREST artifacts to show up when the text was positioned at a subpixel offset in some cases. Instead, we pixel-align the coordinates after mapping them to the view frustum, but before applying the projection to the screen. To make it easier to modify the buffer layout for the shaders the next time, this also adds some constants for offsets. [ChangeLog][Text] Fixed an issue where text using NativeRendering would look slightly skewed if it was inside a parent that had been positioned at a subpixel offset. Fixes: QTBUG-96112 Fixes: QTBUG-83626 Task-number: QTBUG-55638 Change-Id: Ifb785ad5830093df94afc75a7bc288e24ca7aa38 Reviewed-by: Eirik Aavitsland (cherry picked from commit b21948f5e811ce1b7abf065bc48af61a231e86f4) Reviewed-by: Qt Cherry-pick Bot --- src/quick/scenegraph/qsgdefaultglyphnode_p.cpp | 46 +++++++---- src/quick/scenegraph/shaders_ng/24bittextmask.frag | 5 +- .../scenegraph/shaders_ng/32bitcolortext.frag | 5 +- src/quick/scenegraph/shaders_ng/8bittextmask.frag | 3 +- .../scenegraph/shaders_ng/8bittextmask_a.frag | 3 +- src/quick/scenegraph/shaders_ng/outlinedtext.frag | 5 +- src/quick/scenegraph/shaders_ng/outlinedtext.vert | 9 ++- .../scenegraph/shaders_ng/outlinedtext_a.frag | 5 +- src/quick/scenegraph/shaders_ng/styledtext.frag | 3 +- src/quick/scenegraph/shaders_ng/styledtext.vert | 7 +- src/quick/scenegraph/shaders_ng/styledtext_a.frag | 3 +- src/quick/scenegraph/shaders_ng/textmask.frag | 3 +- src/quick/scenegraph/shaders_ng/textmask.vert | 7 +- .../text_nativerendering_subpixelpositions.qml | 91 ++++++++++++++++++++++ 14 files changed, 155 insertions(+), 40 deletions(-) create mode 100644 tests/manual/scenegraph_lancelot/data/text/text_nativerendering_subpixelpositions.qml diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp index 95a52a599d..7af1dc9b01 100644 --- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp +++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp @@ -428,6 +428,18 @@ QSGTextMaskRhiShader::QSGTextMaskRhiShader(QFontEngine::GlyphFormat glyphFormat) QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/textmask.frag.qsb")); } +enum UbufOffset { + ModelViewMatrixOffset = 0, + ProjectionMatrixOffset = ModelViewMatrixOffset + 64, + ColorOffset = ProjectionMatrixOffset + 64, + TextureScaleOffset = ColorOffset + 16, + DprOffset = TextureScaleOffset + 8, + + // + 1 float padding (vec4 must be aligned to 16) + StyleColorOffset = DprOffset + 4 + 4, + ShiftOffset = StyleColorOffset + 16 +}; + bool QSGTextMaskRhiShader::updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) { @@ -443,11 +455,14 @@ bool QSGTextMaskRhiShader::updateUniformData(RenderState &state, bool changed = false; QByteArray *buf = state.uniformData(); - Q_ASSERT(buf->size() >= 92); + Q_ASSERT(buf->size() >= DprOffset + 4); if (state.isMatrixDirty()) { - const QMatrix4x4 m = state.combinedMatrix(); - memcpy(buf->data(), m.constData(), 64); + const QMatrix4x4 mv = state.modelViewMatrix(); + memcpy(buf->data() + ModelViewMatrixOffset, mv.constData(), 64); + const QMatrix4x4 p = state.projectionMatrix(); + memcpy(buf->data() + ProjectionMatrixOffset, p.constData(), 64); + changed = true; } @@ -456,13 +471,13 @@ bool QSGTextMaskRhiShader::updateUniformData(RenderState &state, 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); + memcpy(buf->data() + TextureScaleOffset, &textureScale, 8); changed = true; } if (!oldMat) { float dpr = state.devicePixelRatio(); - memcpy(buf->data() + 64 + 16 + 8, &dpr, 4); + memcpy(buf->data() + DprOffset, &dpr, 4); } // move texture uploads/copies onto the renderer's soon-to-be-committed list @@ -510,11 +525,11 @@ bool QSG8BitTextMaskRhiShader::updateUniformData(RenderState &state, QSGTextMaskMaterial *oldMat = static_cast(oldMaterial); QByteArray *buf = state.uniformData(); - Q_ASSERT(buf->size() >= 80); + Q_ASSERT(buf->size() >= ColorOffset + 16); if (oldMat == nullptr || mat->color() != oldMat->color() || state.isOpacityDirty()) { const QVector4D color = qsg_premultiply(mat->color(), state.opacity()); - memcpy(buf->data() + 64, &color, 16); + memcpy(buf->data() + ColorOffset, &color, 16); changed = true; } @@ -553,12 +568,12 @@ bool QSG24BitTextMaskRhiShader::updateUniformData(RenderState &state, QSGTextMaskMaterial *oldMat = static_cast(oldMaterial); QByteArray *buf = state.uniformData(); - Q_ASSERT(buf->size() >= 92); + Q_ASSERT(buf->size() >= ColorOffset + 16); if (oldMat == nullptr || mat->color() != oldMat->color() || state.isOpacityDirty()) { // shader takes vec4 but uses alpha only; coloring happens via the blend constant const QVector4D color = qsg_premultiply(mat->color(), state.opacity()); - memcpy(buf->data() + 64, &color, 16); + memcpy(buf->data() + ColorOffset, &color, 16); changed = true; } @@ -608,12 +623,12 @@ bool QSG32BitColorTextRhiShader::updateUniformData(RenderState &state, QSGTextMaskMaterial *oldMat = static_cast(oldMaterial); QByteArray *buf = state.uniformData(); - Q_ASSERT(buf->size() >= 92); + Q_ASSERT(buf->size() >= ColorOffset + 16); if (oldMat == nullptr || mat->color() != oldMat->color() || state.isOpacityDirty()) { // shader takes vec4 but uses alpha only const QVector4D color(0, 0, 0, mat->color().w() * state.opacity()); - memcpy(buf->data() + 64, &color, 16); + memcpy(buf->data() + ColorOffset, &color, 16); changed = true; } @@ -649,20 +664,17 @@ bool QSGStyledTextRhiShader::updateUniformData(RenderState &state, QSGStyledTextMaterial *oldMat = static_cast(oldMaterial); QByteArray *buf = state.uniformData(); - Q_ASSERT(buf->size() >= 120); - - // matrix..dpr + 1 float padding (vec4 must be aligned to 16) - const int startOffset = 64 + 16 + 8 + 4 + 4; + Q_ASSERT(buf->size() >= ShiftOffset + 8); if (oldMat == nullptr || mat->styleColor() != oldMat->styleColor() || state.isOpacityDirty()) { const QVector4D styleColor = qsg_premultiply(mat->styleColor(), state.opacity()); - memcpy(buf->data() + startOffset, &styleColor, 16); + memcpy(buf->data() + StyleColorOffset, &styleColor, 16); changed = true; } if (oldMat == nullptr || oldMat->styleShift() != mat->styleShift()) { const QVector2D v = mat->styleShift(); - memcpy(buf->data() + startOffset + 16, &v, 8); + memcpy(buf->data() + ShiftOffset, &v, 8); changed = true; } diff --git a/src/quick/scenegraph/shaders_ng/24bittextmask.frag b/src/quick/scenegraph/shaders_ng/24bittextmask.frag index bc3826a924..ed8da4cd30 100644 --- a/src/quick/scenegraph/shaders_ng/24bittextmask.frag +++ b/src/quick/scenegraph/shaders_ng/24bittextmask.frag @@ -6,8 +6,9 @@ layout(location = 0) out vec4 fragColor; layout(binding = 1) uniform sampler2D _qt_texture; layout(std140, binding = 0) uniform buf { - mat4 matrix; - vec4 color; // only alpha is used, but must be vec4 due to layout compat + mat4 modelViewMatrix; + mat4 projectionMatrix; + vec4 color; vec2 textureScale; float dpr; } ubuf; diff --git a/src/quick/scenegraph/shaders_ng/32bitcolortext.frag b/src/quick/scenegraph/shaders_ng/32bitcolortext.frag index 63e445f90b..4198a4d339 100644 --- a/src/quick/scenegraph/shaders_ng/32bitcolortext.frag +++ b/src/quick/scenegraph/shaders_ng/32bitcolortext.frag @@ -6,8 +6,9 @@ layout(location = 0) out vec4 fragColor; layout(binding = 1) uniform sampler2D _qt_texture; layout(std140, binding = 0) uniform buf { - mat4 matrix; - vec4 color; // only alpha is used, but must be vec4 due to layout compat + mat4 modelViewMatrix; + mat4 projectionMatrix; + vec4 color; vec2 textureScale; float dpr; } ubuf; diff --git a/src/quick/scenegraph/shaders_ng/8bittextmask.frag b/src/quick/scenegraph/shaders_ng/8bittextmask.frag index 6304e821ff..a06743876d 100644 --- a/src/quick/scenegraph/shaders_ng/8bittextmask.frag +++ b/src/quick/scenegraph/shaders_ng/8bittextmask.frag @@ -6,7 +6,8 @@ layout(location = 0) out vec4 fragColor; layout(binding = 1) uniform sampler2D _qt_texture; layout(std140, binding = 0) uniform buf { - mat4 matrix; + mat4 modelViewMatrix; + mat4 projectionMatrix; vec4 color; vec2 textureScale; float dpr; diff --git a/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag b/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag index 0d0fa1cd3a..f725cbc5e7 100644 --- a/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag +++ b/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag @@ -6,7 +6,8 @@ layout(location = 0) out vec4 fragColor; layout(binding = 1) uniform sampler2D _qt_texture; layout(std140, binding = 0) uniform buf { - mat4 matrix; + mat4 modelViewMatrix; + mat4 projectionMatrix; vec4 color; vec2 textureScale; float dpr; diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext.frag b/src/quick/scenegraph/shaders_ng/outlinedtext.frag index 947d161a50..e2f82d3845 100644 --- a/src/quick/scenegraph/shaders_ng/outlinedtext.frag +++ b/src/quick/scenegraph/shaders_ng/outlinedtext.frag @@ -11,11 +11,12 @@ layout(location = 0) out vec4 fragColor; layout(binding = 1) uniform sampler2D _qt_texture; layout(std140, binding = 0) uniform buf { - // must match styledtext - mat4 matrix; + mat4 modelViewMatrix; + mat4 projectionMatrix; vec4 color; vec2 textureScale; float dpr; + // the above must stay compatible with textmask/8bittextmask vec4 styleColor; vec2 shift; } ubuf; diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext.vert b/src/quick/scenegraph/shaders_ng/outlinedtext.vert index 023f9dfdc2..4068e42f28 100644 --- a/src/quick/scenegraph/shaders_ng/outlinedtext.vert +++ b/src/quick/scenegraph/shaders_ng/outlinedtext.vert @@ -10,11 +10,12 @@ layout(location = 3) out vec2 sCoordLeft; layout(location = 4) out vec2 sCoordRight; layout(std140, binding = 0) uniform buf { - // must match styledtext - mat4 matrix; + mat4 modelViewMatrix; + mat4 projectionMatrix; vec4 color; vec2 textureScale; float dpr; + // the above must stay compatible with textmask/8bittextmask vec4 styleColor; vec2 shift; } ubuf; @@ -28,6 +29,6 @@ void main() sCoordDown = (tCoord - vec2(0.0, 1.0)) * ubuf.textureScale; sCoordLeft = (tCoord - vec2(-1.0, 0.0)) * ubuf.textureScale; sCoordRight = (tCoord - vec2(1.0, 0.0)) * ubuf.textureScale; - vec3 dprSnapPos = floor(vCoord.xyz * ubuf.dpr + 0.5) / ubuf.dpr; - gl_Position = ubuf.matrix * vec4(dprSnapPos, vCoord.w); + vec4 xformed = ubuf.modelViewMatrix * vCoord; + gl_Position = ubuf.projectionMatrix * vec4(floor(xformed.xyz * ubuf.dpr + 0.5) / ubuf.dpr, xformed.w); } diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag b/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag index 5b7bd9ca82..274d891a3c 100644 --- a/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag +++ b/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag @@ -11,11 +11,12 @@ layout(location = 0) out vec4 fragColor; layout(binding = 1) uniform sampler2D _qt_texture; layout(std140, binding = 0) uniform buf { - // must match styledtext - mat4 matrix; + mat4 modelViewMatrix; + mat4 projectionMatrix; vec4 color; vec2 textureScale; float dpr; + // the above must stay compatible with textmask/8bittextmask vec4 styleColor; vec2 shift; } ubuf; diff --git a/src/quick/scenegraph/shaders_ng/styledtext.frag b/src/quick/scenegraph/shaders_ng/styledtext.frag index 0b16396037..2e380dfeae 100644 --- a/src/quick/scenegraph/shaders_ng/styledtext.frag +++ b/src/quick/scenegraph/shaders_ng/styledtext.frag @@ -8,7 +8,8 @@ layout(location = 0) out vec4 fragColor; layout(binding = 1) uniform sampler2D _qt_texture; layout(std140, binding = 0) uniform buf { - mat4 matrix; + mat4 modelViewMatrix; + mat4 projectionMatrix; vec4 color; vec2 textureScale; float dpr; diff --git a/src/quick/scenegraph/shaders_ng/styledtext.vert b/src/quick/scenegraph/shaders_ng/styledtext.vert index beadf07c79..271dae8d8a 100644 --- a/src/quick/scenegraph/shaders_ng/styledtext.vert +++ b/src/quick/scenegraph/shaders_ng/styledtext.vert @@ -7,7 +7,8 @@ layout(location = 0) out vec2 sampleCoord; layout(location = 1) out vec2 shiftedSampleCoord; layout(std140, binding = 0) uniform buf { - mat4 matrix; + mat4 modelViewMatrix; + mat4 projectionMatrix; vec4 color; vec2 textureScale; float dpr; @@ -22,6 +23,6 @@ void main() { sampleCoord = tCoord * ubuf.textureScale; shiftedSampleCoord = (tCoord - ubuf.shift) * ubuf.textureScale; - vec3 dprSnapPos = floor(vCoord.xyz * ubuf.dpr + 0.5) / ubuf.dpr; - gl_Position = ubuf.matrix * vec4(dprSnapPos, vCoord.w); + vec4 xformed = ubuf.modelViewMatrix * vCoord; + gl_Position = ubuf.projectionMatrix * vec4(floor(xformed.xyz * ubuf.dpr + 0.5) / ubuf.dpr, xformed.w); } diff --git a/src/quick/scenegraph/shaders_ng/styledtext_a.frag b/src/quick/scenegraph/shaders_ng/styledtext_a.frag index b673137895..62e162c851 100644 --- a/src/quick/scenegraph/shaders_ng/styledtext_a.frag +++ b/src/quick/scenegraph/shaders_ng/styledtext_a.frag @@ -8,7 +8,8 @@ layout(location = 0) out vec4 fragColor; layout(binding = 1) uniform sampler2D _qt_texture; layout(std140, binding = 0) uniform buf { - mat4 matrix; + mat4 modelViewMatrix; + mat4 projectionMatrix; vec4 color; vec2 textureScale; float dpr; diff --git a/src/quick/scenegraph/shaders_ng/textmask.frag b/src/quick/scenegraph/shaders_ng/textmask.frag index 518d5c965f..ed8da4cd30 100644 --- a/src/quick/scenegraph/shaders_ng/textmask.frag +++ b/src/quick/scenegraph/shaders_ng/textmask.frag @@ -6,7 +6,8 @@ layout(location = 0) out vec4 fragColor; layout(binding = 1) uniform sampler2D _qt_texture; layout(std140, binding = 0) uniform buf { - mat4 matrix; + mat4 modelViewMatrix; + mat4 projectionMatrix; vec4 color; vec2 textureScale; float dpr; diff --git a/src/quick/scenegraph/shaders_ng/textmask.vert b/src/quick/scenegraph/shaders_ng/textmask.vert index 9d80d5dadb..e0b3c01bce 100644 --- a/src/quick/scenegraph/shaders_ng/textmask.vert +++ b/src/quick/scenegraph/shaders_ng/textmask.vert @@ -6,7 +6,8 @@ layout(location = 1) in vec2 tCoord; layout(location = 0) out vec2 sampleCoord; layout(std140, binding = 0) uniform buf { - mat4 matrix; + mat4 modelViewMatrix; + mat4 projectionMatrix; vec4 color; vec2 textureScale; float dpr; @@ -17,6 +18,6 @@ out gl_PerVertex { vec4 gl_Position; }; void main() { sampleCoord = tCoord * ubuf.textureScale; - vec3 dprSnapPos = floor(vCoord.xyz * ubuf.dpr + 0.5) / ubuf.dpr; - gl_Position = ubuf.matrix * vec4(dprSnapPos, vCoord.w); + vec4 xformed = ubuf.modelViewMatrix * vCoord; + gl_Position = ubuf.projectionMatrix * vec4(floor(xformed.xyz * ubuf.dpr + 0.5) / ubuf.dpr, xformed.w); } diff --git a/tests/manual/scenegraph_lancelot/data/text/text_nativerendering_subpixelpositions.qml b/tests/manual/scenegraph_lancelot/data/text/text_nativerendering_subpixelpositions.qml new file mode 100644 index 0000000000..c60fc4d8b0 --- /dev/null +++ b/tests/manual/scenegraph_lancelot/data/text/text_nativerendering_subpixelpositions.qml @@ -0,0 +1,91 @@ +import QtQuick 2.0 + +//vary font style, native rendering at non-integer offsets + +Item { + id: topLevel + width: 320 + height: 580 + + Repeater { + model: [Text.Normal, Text.Outline, Text.Raised, Text.Sunken] + Text { + y: 20 * index + clip: true + renderType: Text.NativeRendering + width: parent.width + wrapMode: Text.Wrap + font.pointSize: 10 + style: modelData + styleColor: "green" + text: "The quick fox jumps in style " + modelData + } + } + + Repeater { + model: [Text.Normal, Text.Outline, Text.Raised, Text.Sunken] + Text { + y: 100.5 + 20 * index + clip: true + renderType: Text.NativeRendering + width: parent.width + wrapMode: Text.Wrap + font.pointSize: 10 + style: modelData + styleColor: "green" + text: "The quick fox jumps in style " + modelData + } + } + + Repeater { + model: [Text.Normal, Text.Outline, Text.Raised, Text.Sunken] + Text { + y: 200.5 + 20 * index + x: 0.5 + clip: true + renderType: Text.NativeRendering + width: parent.width + wrapMode: Text.Wrap + font.pointSize: 10 + style: modelData + styleColor: "green" + text: "The quick fox jumps in style " + modelData + } + } + + Repeater { + model: [Text.Normal, Text.Outline, Text.Raised, Text.Sunken] + Text { + y: 300.5 + 20 * index + x: 0.5 + clip: true + renderType: Text.NativeRendering + width: parent.width + wrapMode: Text.Wrap + font.pointSize: 10 + style: modelData + styleColor: "green" + text: "The quick fox jumps in style " + modelData + } + } + + Repeater { + model: [Text.Normal, Text.Outline, Text.Raised, Text.Sunken] + Rectangle { + y: 400.5 + 20 * index + x: 0.5 + width: topLevel.width + height: topLevel.height + clip: true + Text { + renderType: Text.NativeRendering + width: parent.width + wrapMode: Text.Wrap + font.pointSize: 10 + style: modelData + styleColor: "green" + text: "The quick fox jumps in style " + modelData + } + } + } +} -- cgit v1.2.3