Compare commits
No commits in common. 'i10ce' and 'c9' have entirely different histories.
@ -1 +1 @@
|
||||
SOURCES/qtdeclarative-everywhere-opensource-src-5.15.15.tar.xz
|
||||
SOURCES/qtdeclarative-everywhere-opensource-src-5.15.9.tar.xz
|
||||
|
@ -1 +1 @@
|
||||
04598aaa01a546648769e85e2e225047d153e7a8 SOURCES/qtdeclarative-everywhere-opensource-src-5.15.15.tar.xz
|
||||
c1230f5c709f80d5bf7e61456a7d605983201cde SOURCES/qtdeclarative-everywhere-opensource-src-5.15.9.tar.xz
|
||||
|
@ -0,0 +1,113 @@
|
||||
From 7be5422134167fe6d9fd44ef683f407bbda1bce7 Mon Sep 17 00:00:00 2001
|
||||
From: Ulf Hermann <ulf.hermann@qt.io>
|
||||
Date: Tue, 30 Nov 2021 14:39:48 +0100
|
||||
Subject: [PATCH 14/19] Qml: Don't crash when as-casting to type with errors
|
||||
|
||||
Such types don't have a compilation unit, but we still know their names.
|
||||
|
||||
Pick-to: 6.2
|
||||
Fixes: QTBUG-98792
|
||||
Change-Id: I2db8dea3a5a02ec1492f7f7a054fd3ad4c6ad69a
|
||||
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
||||
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
|
||||
(cherry picked from commit e0cd201e91ae64b9c03e0128cd17656b00611fbb)
|
||||
---
|
||||
src/qml/qml/qqmltypewrapper.cpp | 6 ++++--
|
||||
src/qml/types/qqmlconnections.cpp | 2 +-
|
||||
tests/auto/qml/qqmllanguage/data/Broken.qml | 5 +++++
|
||||
tests/auto/qml/qqmllanguage/data/asBroken.qml | 6 ++++++
|
||||
tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 16 ++++++++++++++++
|
||||
5 files changed, 32 insertions(+), 3 deletions(-)
|
||||
create mode 100644 tests/auto/qml/qqmllanguage/data/Broken.qml
|
||||
create mode 100644 tests/auto/qml/qqmllanguage/data/asBroken.qml
|
||||
|
||||
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
|
||||
index 175de8b936..a6ba4b8cb3 100644
|
||||
--- a/src/qml/qml/qqmltypewrapper.cpp
|
||||
+++ b/src/qml/qml/qqmltypewrapper.cpp
|
||||
@@ -419,8 +419,10 @@ ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const
|
||||
return Encode(false);
|
||||
|
||||
QQmlRefPointer<QQmlTypeData> td = qenginepriv->typeLoader.getType(typeWrapper->d()->type().sourceUrl());
|
||||
- ExecutableCompilationUnit *cu = td->compilationUnit();
|
||||
- myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId);
|
||||
+ if (ExecutableCompilationUnit *cu = td->compilationUnit())
|
||||
+ myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId);
|
||||
+ else
|
||||
+ return Encode(false); // It seems myQmlType has some errors, so we could not compile it.
|
||||
} else {
|
||||
myQmlType = qenginepriv->metaObjectForType(myTypeId);
|
||||
}
|
||||
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
|
||||
index 29ed62cd39..aba930dfe1 100644
|
||||
--- a/src/qml/types/qqmlconnections.cpp
|
||||
+++ b/src/qml/types/qqmlconnections.cpp
|
||||
@@ -338,7 +338,7 @@ void QQmlConnections::connectSignalsToMethods()
|
||||
&& 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);
|
||||
+ "signal of the \"%2\" target matches the name.").arg(propName).arg(target->metaObject()->className());
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/tests/auto/qml/qqmllanguage/data/Broken.qml b/tests/auto/qml/qqmllanguage/data/Broken.qml
|
||||
new file mode 100644
|
||||
index 0000000000..e24d9112a8
|
||||
--- /dev/null
|
||||
+++ b/tests/auto/qml/qqmllanguage/data/Broken.qml
|
||||
@@ -0,0 +1,5 @@
|
||||
+import QtQml 2.15
|
||||
+
|
||||
+QtObject {
|
||||
+ notThere: 5
|
||||
+}
|
||||
diff --git a/tests/auto/qml/qqmllanguage/data/asBroken.qml b/tests/auto/qml/qqmllanguage/data/asBroken.qml
|
||||
new file mode 100644
|
||||
index 0000000000..bd88d14c76
|
||||
--- /dev/null
|
||||
+++ b/tests/auto/qml/qqmllanguage/data/asBroken.qml
|
||||
@@ -0,0 +1,6 @@
|
||||
+import QtQml 2.15
|
||||
+
|
||||
+QtObject {
|
||||
+ id: self
|
||||
+ property var selfAsBroken: self as Broken
|
||||
+}
|
||||
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
|
||||
index bffb62c59e..97cc64991f 100644
|
||||
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
|
||||
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
|
||||
@@ -336,6 +336,7 @@ private slots:
|
||||
void bareInlineComponent();
|
||||
|
||||
void hangOnWarning();
|
||||
+ void objectAsBroken();
|
||||
|
||||
void ambiguousContainingType();
|
||||
|
||||
@@ -5876,6 +5877,21 @@ void tst_qqmllanguage::ambiguousContainingType()
|
||||
}
|
||||
}
|
||||
|
||||
+void tst_qqmllanguage::objectAsBroken()
|
||||
+{
|
||||
+ QQmlEngine engine;
|
||||
+ QQmlComponent c(&engine, testFileUrl("asBroken.qml"));
|
||||
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
|
||||
+ QScopedPointer<QObject> o(c.create());
|
||||
+ QVERIFY(!o.isNull());
|
||||
+ QVariant selfAsBroken = o->property("selfAsBroken");
|
||||
+ QVERIFY(selfAsBroken.isValid());
|
||||
+ // QCOMPARE(selfAsBroken.metaType(), QMetaType::fromType<std::nullptr_t>());
|
||||
+
|
||||
+ QQmlComponent b(&engine, testFileUrl("Broken.qml"));
|
||||
+ QVERIFY(b.isError());
|
||||
+}
|
||||
+
|
||||
QTEST_MAIN(tst_qqmllanguage)
|
||||
|
||||
#include "tst_qqmllanguage.moc"
|
||||
--
|
||||
2.40.0
|
||||
|
@ -0,0 +1,54 @@
|
||||
From d54b978c0cba2bf75e145c9e1b00d2a9ab495d70 Mon Sep 17 00:00:00 2001
|
||||
From: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
|
||||
Date: Mon, 19 Dec 2022 10:05:33 +0100
|
||||
Subject: [PATCH 15/19] Fix missing glyphs when using NativeRendering
|
||||
|
||||
When we look up glyphs with subpixel positions in the glyph cache,
|
||||
we use the calculated subpixel position (from a set of predefined
|
||||
subpixel positions) as key. In some very rare cases, we could end
|
||||
up with different subpixel positions when looking up an on-screen
|
||||
position than when we entered it into the cache, due to numerical
|
||||
differences when doing the calculation.
|
||||
|
||||
The reason for this was that when entering the glyph into the
|
||||
cache, we used the 16.6 fixed point representation, whereas when
|
||||
looking up, we used the unmodified float. In some cases, the
|
||||
converted fixed point approximation might snap to a different
|
||||
predefined subpixel position than the floating point equivalent.
|
||||
|
||||
To avoid this, we reuse the converted fixed point positions when
|
||||
looking up the glyphs in the cache.
|
||||
|
||||
[ChangeLog][Text] Fixed an issue where text using NativeRendering
|
||||
would sometimes be missing glyphs.
|
||||
|
||||
Pick-to: 5.15 6.2 6.4 6.5
|
||||
Fixes: QTBUG-108713
|
||||
Change-Id: Iecc264eb3d27e875c24257eaefcfb18a1a5fb5be
|
||||
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
|
||||
Reviewed-by: Lars Knoll <lars@knoll.priv.no>
|
||||
(cherry picked from commit 4bad329985b75090c68a70cceee7edadc172d7ab)
|
||||
---
|
||||
src/quick/scenegraph/qsgdefaultglyphnode_p.cpp | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
|
||||
index f912da5799..fd128aa06e 100644
|
||||
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
|
||||
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
|
||||
@@ -839,9 +839,11 @@ void QSGTextMaskMaterial::populate(const QPointF &p,
|
||||
bool supportsSubPixelPositions = fontD->fontEngine->supportsSubPixelPositions();
|
||||
for (int i=0; i<glyphIndexes.size(); ++i) {
|
||||
QPointF glyphPosition = glyphPositions.at(i) + position;
|
||||
+ QFixedPoint fixedPointPosition = fixedPointPositions.at(i);
|
||||
+
|
||||
QFixed subPixelPosition;
|
||||
if (supportsSubPixelPositions)
|
||||
- subPixelPosition = fontD->fontEngine->subPixelPositionForX(QFixed::fromReal(glyphPosition.x()));
|
||||
+ subPixelPosition = fontD->fontEngine->subPixelPositionForX(QFixed::fromReal(fixedPointPosition.x.toReal() * glyphCacheScaleX));
|
||||
|
||||
QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphIndexes.at(i), subPixelPosition);
|
||||
const QTextureGlyphCache::Coord &c = cache->coords.value(glyph);
|
||||
--
|
||||
2.40.0
|
||||
|
@ -1,51 +0,0 @@
|
||||
From 7882c22b04ecd7bc349d3d585b3de860b2c64781 Mon Sep 17 00:00:00 2001
|
||||
From: Ulf Hermann <ulf.hermann@qt.io>
|
||||
Date: Wed, 29 Mar 2023 16:36:03 +0200
|
||||
Subject: [PATCH 15/25] Models: Avoid crashes when deleting cache items
|
||||
|
||||
Pick-to: 6.5 6.2 5.15
|
||||
Fixes: QTBUG-91425
|
||||
Change-Id: I58cf9ee29922f83fc6621f771b80ed557b31f106
|
||||
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
|
||||
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
||||
(cherry picked from commit 0cfdecba54e4f40468c4c9a8a6668cc1bc0eff65)
|
||||
|
||||
* asturmlechner 2023-04-08: Resolve conflict with dev branch commit
|
||||
c2d490a2385ea6f389340a296acaac0fa198c8b9 (qAsConst to std::as_const)
|
||||
---
|
||||
.../qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp | 12 ++++++++++++
|
||||
1 file changed, 12 insertions(+)
|
||||
|
||||
diff --git a/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp b/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp
|
||||
index e128d77c52..e5daf2d28b 100644
|
||||
--- a/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp
|
||||
+++ b/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp
|
||||
@@ -51,6 +51,7 @@ private slots:
|
||||
void contextAccessedByHandler();
|
||||
void deleteRace();
|
||||
void redrawUponColumnChange();
|
||||
+ void deleteRace();
|
||||
};
|
||||
|
||||
class AbstractItemModel : public QAbstractItemModel
|
||||
@@ -214,6 +215,17 @@ void tst_QQmlDelegateModel::redrawUponColumnChange()
|
||||
QCOMPARE(item->property("text").toString(), "Coconut");
|
||||
}
|
||||
|
||||
+void tst_QQmlDelegateModel::deleteRace()
|
||||
+{
|
||||
+ QQmlEngine engine;
|
||||
+ QQmlComponent c(&engine, testFileUrl("deleteRace.qml"));
|
||||
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
|
||||
+ QScopedPointer<QObject> o(c.create());
|
||||
+ QVERIFY(!o.isNull());
|
||||
+ QTRY_COMPARE(o->property("count").toInt(), 2);
|
||||
+ QTRY_COMPARE(o->property("count").toInt(), 0);
|
||||
+}
|
||||
+
|
||||
QTEST_MAIN(tst_QQmlDelegateModel)
|
||||
|
||||
#include "tst_qqmldelegatemodel.moc"
|
||||
--
|
||||
2.46.0
|
||||
|
@ -0,0 +1,32 @@
|
||||
From 70b44dd18b9727e9aae857297265a751700a297e Mon Sep 17 00:00:00 2001
|
||||
From: Fushan Wen <qydwhotmail@gmail.com>
|
||||
Date: Tue, 10 Jan 2023 20:42:04 +0800
|
||||
Subject: [PATCH 16/19] Revert "Fix missing glyphs when using NativeRendering"
|
||||
|
||||
This reverts commit da5e53b649f50cd9cdd89dadbba16f05e4070be2.
|
||||
|
||||
It breaks fonts on Wayland when global scale > 100%.
|
||||
---
|
||||
src/quick/scenegraph/qsgdefaultglyphnode_p.cpp | 4 +---
|
||||
1 file changed, 1 insertion(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
|
||||
index fd128aa06e..f912da5799 100644
|
||||
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
|
||||
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
|
||||
@@ -839,11 +839,9 @@ void QSGTextMaskMaterial::populate(const QPointF &p,
|
||||
bool supportsSubPixelPositions = fontD->fontEngine->supportsSubPixelPositions();
|
||||
for (int i=0; i<glyphIndexes.size(); ++i) {
|
||||
QPointF glyphPosition = glyphPositions.at(i) + position;
|
||||
- QFixedPoint fixedPointPosition = fixedPointPositions.at(i);
|
||||
-
|
||||
QFixed subPixelPosition;
|
||||
if (supportsSubPixelPositions)
|
||||
- subPixelPosition = fontD->fontEngine->subPixelPositionForX(QFixed::fromReal(fixedPointPosition.x.toReal() * glyphCacheScaleX));
|
||||
+ subPixelPosition = fontD->fontEngine->subPixelPositionForX(QFixed::fromReal(glyphPosition.x()));
|
||||
|
||||
QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphIndexes.at(i), subPixelPosition);
|
||||
const QTextureGlyphCache::Coord &c = cache->coords.value(glyph);
|
||||
--
|
||||
2.40.0
|
||||
|
@ -1,35 +0,0 @@
|
||||
From e2c7bdca3d1442b9e4e265378ee17b9ac347b4c3 Mon Sep 17 00:00:00 2001
|
||||
From: Maximilian Goldstein <max.goldstein@qt.io>
|
||||
Date: Wed, 9 Jun 2021 15:02:45 +0200
|
||||
Subject: [PATCH 16/25] qv4function: Fix crash due to reference being
|
||||
invalidated
|
||||
|
||||
Function::updateInternalClass creates a reference to a QStringList that is appended to before being used.
|
||||
This is unsafe and can leads to a segfault if the append() causes a reallocation.
|
||||
|
||||
Fixes: QTBUG-94360
|
||||
Pick-to: 5.15 6.1 6.2
|
||||
Change-Id: Iac49e8d816cf440ca2b70e133c88314eb8df6b91
|
||||
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
||||
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
|
||||
(cherry picked from commit 7fa28f98824a94396106eadfc028b329985a0cfc)
|
||||
---
|
||||
src/qml/jsruntime/qv4function.cpp | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
|
||||
index cf8a53cf9f..223e64271e 100644
|
||||
--- a/src/qml/jsruntime/qv4function.cpp
|
||||
+++ b/src/qml/jsruntime/qv4function.cpp
|
||||
@@ -136,7 +136,7 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArr
|
||||
if (duplicate == -1) {
|
||||
parameterNames.append(QString::fromUtf8(param));
|
||||
} else {
|
||||
- const QString &dup = parameterNames[duplicate];
|
||||
+ const QString dup = parameterNames[duplicate];
|
||||
parameterNames.append(dup);
|
||||
parameterNames[duplicate] =
|
||||
QString(0xfffe) + QString::number(duplicate) + dup;
|
||||
--
|
||||
2.46.0
|
||||
|
@ -1,141 +0,0 @@
|
||||
From 980ed9bae736634ed6edf2d2b85b91bdb90e4f19 Mon Sep 17 00:00:00 2001
|
||||
From: Fabian Kosmale <fabian.kosmale@qt.io>
|
||||
Date: Tue, 29 Mar 2022 10:44:04 +0200
|
||||
Subject: [PATCH 17/25] Quick Animations: Fix crash
|
||||
|
||||
SwipeDelegate causes the running animation job to be deleted when
|
||||
calling swipe.close in swipe.completed. Employ the RETURN_IF_DELETED
|
||||
check in more places to avoid crashes.
|
||||
|
||||
Fixes: QTBUG-100560
|
||||
Task-number: QTBUG-103223
|
||||
Pick-to: 6.3 6.2 5.15
|
||||
Change-Id: I276eeaa9aed1bdb36449b322a24641fa02c4d5e4
|
||||
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
|
||||
(cherry picked from commit 0238af0bd48b831d72126f2228d5913eccf67bae)
|
||||
|
||||
* asturmlechner 2023-04-09: Resolve conflict with dev branch commit
|
||||
4938984f9a779192264757a06e6ca555fc8f5e91
|
||||
---
|
||||
.../qcontinuinganimationgroupjob.cpp | 4 +-
|
||||
.../animations/qparallelanimationgroupjob.cpp | 4 +-
|
||||
.../swipedelegate/CloseOnCompletedWorks.qml | 74 +++++++++++++++++++
|
||||
3 files changed, 78 insertions(+), 4 deletions(-)
|
||||
create mode 100644 tests/manual/quickcontrols2/swipedelegate/CloseOnCompletedWorks.qml
|
||||
|
||||
diff --git a/src/qml/animations/qcontinuinganimationgroupjob.cpp b/src/qml/animations/qcontinuinganimationgroupjob.cpp
|
||||
index 88c0e9e60e..61a9dc36f8 100644
|
||||
--- a/src/qml/animations/qcontinuinganimationgroupjob.cpp
|
||||
+++ b/src/qml/animations/qcontinuinganimationgroupjob.cpp
|
||||
@@ -82,9 +82,9 @@ void QContinuingAnimationGroupJob::updateState(QAbstractAnimationJob::State newS
|
||||
return;
|
||||
}
|
||||
for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
|
||||
- resetUncontrolledAnimationFinishTime(animation);
|
||||
+ RETURN_IF_DELETED(resetUncontrolledAnimationFinishTime(animation));
|
||||
animation->setDirection(m_direction);
|
||||
- animation->start();
|
||||
+ RETURN_IF_DELETED(animation->start());
|
||||
}
|
||||
break;
|
||||
}
|
||||
diff --git a/src/qml/animations/qparallelanimationgroupjob.cpp b/src/qml/animations/qparallelanimationgroupjob.cpp
|
||||
index 420a934ba2..a828d0e234 100644
|
||||
--- a/src/qml/animations/qparallelanimationgroupjob.cpp
|
||||
+++ b/src/qml/animations/qparallelanimationgroupjob.cpp
|
||||
@@ -144,10 +144,10 @@ void QParallelAnimationGroupJob::updateState(QAbstractAnimationJob::State newSta
|
||||
animation->stop();
|
||||
m_previousLoop = m_direction == Forward ? 0 : m_loopCount - 1;
|
||||
}
|
||||
- resetUncontrolledAnimationFinishTime(animation);
|
||||
+ RETURN_IF_DELETED(resetUncontrolledAnimationFinishTime(animation));
|
||||
animation->setDirection(m_direction);
|
||||
if (shouldAnimationStart(animation, oldState == Stopped))
|
||||
- animation->start();
|
||||
+ RETURN_IF_DELETED(animation->start());
|
||||
}
|
||||
break;
|
||||
}
|
||||
diff --git a/tests/manual/quickcontrols2/swipedelegate/CloseOnCompletedWorks.qml b/tests/manual/quickcontrols2/swipedelegate/CloseOnCompletedWorks.qml
|
||||
new file mode 100644
|
||||
index 0000000000..38dfde41c3
|
||||
--- /dev/null
|
||||
+++ b/tests/manual/quickcontrols2/swipedelegate/CloseOnCompletedWorks.qml
|
||||
@@ -0,0 +1,74 @@
|
||||
+/****************************************************************************
|
||||
+**
|
||||
+** Copyright (C) 2022 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
|
||||
+import QtQuick.Controls 2
|
||||
+ApplicationWindow {
|
||||
+ visible: true
|
||||
+ width: 640
|
||||
+ height: 480
|
||||
+
|
||||
+ ListView {
|
||||
+ anchors.fill: parent
|
||||
+ model: 2
|
||||
+
|
||||
+ delegate: SwipeDelegate {
|
||||
+ text: "Swipe me left (should not crash)"
|
||||
+
|
||||
+ swipe.right: Label {
|
||||
+ text: "Release (should not crash)"
|
||||
+ }
|
||||
+
|
||||
+ swipe.onCompleted: {
|
||||
+ swipe.close()
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
--
|
||||
2.46.0
|
||||
|
@ -1,129 +0,0 @@
|
||||
From d6d08e3bee98f150cc3182dba9b38996b1409a34 Mon Sep 17 00:00:00 2001
|
||||
From: Joni Poikelin <joni.poikelin@qt.io>
|
||||
Date: Thu, 3 Sep 2020 14:22:26 +0300
|
||||
Subject: [PATCH 18/25] Prevent crash when destroying asynchronous Loader
|
||||
|
||||
Fixes: QTBUG-86255
|
||||
Pick-to: 5.15
|
||||
Change-Id: I30488b64d910a1409a43e2e98ee7ab084aec33d2
|
||||
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
|
||||
(cherry picked from commit 149c1dd07b54ee0c027d94a49d52160dc4f4e2ac)
|
||||
|
||||
* asturmlechner 2023-01-06: Resolve conflict with dev branch commits
|
||||
d51c007ecc8aa6256cb95cf3992e5ac34a70fa3f and
|
||||
b2a4a61e8cb0839ba293783ac03c72f35c7b1307
|
||||
---
|
||||
src/qml/qml/qqmlvmemetaobject.cpp | 2 +-
|
||||
.../quick/qquickgridview/data/qtbug86255.qml | 55 +++++++++++++++++++
|
||||
.../qquickgridview/tst_qquickgridview.cpp | 13 +++++
|
||||
3 files changed, 69 insertions(+), 1 deletion(-)
|
||||
create mode 100644 tests/auto/quick/qquickgridview/data/qtbug86255.qml
|
||||
|
||||
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
|
||||
index 1e0e4e419f..a0532d1794 100644
|
||||
--- a/src/qml/qml/qqmlvmemetaobject.cpp
|
||||
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
|
||||
@@ -251,7 +251,7 @@ void QQmlVMEMetaObjectEndpoint::tryConnect()
|
||||
if (!pd)
|
||||
return;
|
||||
|
||||
- if (pd->notifyIndex() != -1)
|
||||
+ if (pd->notifyIndex() != -1 && ctxt->engine)
|
||||
connect(target, pd->notifyIndex(), ctxt->engine);
|
||||
}
|
||||
|
||||
diff --git a/tests/auto/quick/qquickgridview/data/qtbug86255.qml b/tests/auto/quick/qquickgridview/data/qtbug86255.qml
|
||||
new file mode 100644
|
||||
index 0000000000..20688b1967
|
||||
--- /dev/null
|
||||
+++ b/tests/auto/quick/qquickgridview/data/qtbug86255.qml
|
||||
@@ -0,0 +1,55 @@
|
||||
+import QtQuick 2.15
|
||||
+
|
||||
+Item {
|
||||
+ width: 240
|
||||
+ height: 320
|
||||
+
|
||||
+ GridView {
|
||||
+ id: grid
|
||||
+ objectName: "view"
|
||||
+ anchors.fill: parent
|
||||
+ cellWidth: 64
|
||||
+ cellHeight: 64
|
||||
+ model: ListModel {
|
||||
+ id: listModel
|
||||
+
|
||||
+ Component.onCompleted: reload()
|
||||
+
|
||||
+ function reload() {
|
||||
+ clear();
|
||||
+ for (let i = 0; i < 1000; i++) {
|
||||
+ let magic = Math.random();
|
||||
+ append( { magic } );
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ clip: true
|
||||
+ delegate: Item {
|
||||
+ id: d
|
||||
+ property string val: magic
|
||||
+ Loader {
|
||||
+ property alias value: d.val
|
||||
+ asynchronous: true
|
||||
+ sourceComponent: cmp
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ Timer {
|
||||
+ running: true
|
||||
+ interval: 1000
|
||||
+ onTriggered: listModel.reload()
|
||||
+ }
|
||||
+ Timer {
|
||||
+ running: true
|
||||
+ interval: 500
|
||||
+ onTriggered: grid.flick(0, -4000)
|
||||
+ }
|
||||
+
|
||||
+ Component {
|
||||
+ id: cmp
|
||||
+ Text {
|
||||
+ text: value
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
|
||||
index 94ec4f44d5..7d0d9fa7a7 100644
|
||||
--- a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
|
||||
+++ b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
|
||||
@@ -213,6 +213,7 @@ private slots:
|
||||
void QTBUG_45640();
|
||||
void QTBUG_49218();
|
||||
void QTBUG_48870_fastModelUpdates();
|
||||
+ void QTBUG_86255();
|
||||
|
||||
void keyNavigationEnabled();
|
||||
void resizeDynamicCellWidthRtL();
|
||||
@@ -6814,6 +6815,18 @@ void tst_QQuickGridView::resizeDynamicCellWidthRtL()
|
||||
QTRY_COMPARE(gridview->contentX(), 0.f);
|
||||
}
|
||||
|
||||
+void tst_QQuickGridView::QTBUG_86255()
|
||||
+{
|
||||
+ QScopedPointer<QQuickView> window(createView());
|
||||
+ window->setSource(testFileUrl("qtbug86255.qml"));
|
||||
+ window->show();
|
||||
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
|
||||
+ QQuickGridView *view = findItem<QQuickGridView>(window->rootObject(), "view");
|
||||
+ QVERIFY(view != nullptr);
|
||||
+ QTRY_COMPARE(view->isFlicking(), true);
|
||||
+ QTRY_COMPARE(view->isFlicking(), false);
|
||||
+}
|
||||
+
|
||||
void tst_QQuickGridView::releaseItems()
|
||||
{
|
||||
QScopedPointer<QQuickView> view(createView());
|
||||
--
|
||||
2.46.0
|
||||
|
@ -0,0 +1,162 @@
|
||||
From 89bf481b9b14f038c5e16421a7fce6dc6523785f Mon Sep 17 00:00:00 2001
|
||||
From: Ulf Hermann <ulf.hermann@qt.io>
|
||||
Date: Wed, 29 Mar 2023 16:36:03 +0200
|
||||
Subject: [PATCH 19/19] Models: Avoid crashes when deleting cache items
|
||||
|
||||
Pick-to: 6.5 6.2 5.15
|
||||
Fixes: QTBUG-91425
|
||||
Change-Id: I58cf9ee29922f83fc6621f771b80ed557b31f106
|
||||
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
|
||||
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
||||
(cherry picked from commit 0cfdecba54e4f40468c4c9a8a6668cc1bc0eff65)
|
||||
|
||||
* asturmlechner 2023-04-08: Resolve conflict with dev branch commit
|
||||
c2d490a2385ea6f389340a296acaac0fa198c8b9 (qAsConst to std::as_const)
|
||||
---
|
||||
src/qmlmodels/qqmldelegatemodel.cpp | 23 ++++++---
|
||||
.../qml/qqmldelegatemodel/data/deleteRace.qml | 50 +++++++++++++++++++
|
||||
.../tst_qqmldelegatemodel.cpp | 12 +++++
|
||||
3 files changed, 78 insertions(+), 7 deletions(-)
|
||||
create mode 100644 tests/auto/qml/qqmldelegatemodel/data/deleteRace.qml
|
||||
|
||||
diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp
|
||||
index bc6b2447af..551e0ede95 100644
|
||||
--- a/src/qmlmodels/qqmldelegatemodel.cpp
|
||||
+++ b/src/qmlmodels/qqmldelegatemodel.cpp
|
||||
@@ -1883,10 +1883,15 @@ void QQmlDelegateModelPrivate::emitChanges()
|
||||
for (int i = 1; i < m_groupCount; ++i)
|
||||
QQmlDelegateModelGroupPrivate::get(m_groups[i])->emitModelUpdated(reset);
|
||||
|
||||
- auto cacheCopy = m_cache; // deliberate; emitChanges may alter m_cache
|
||||
- for (QQmlDelegateModelItem *cacheItem : qAsConst(cacheCopy)) {
|
||||
- if (cacheItem->attached)
|
||||
- cacheItem->attached->emitChanges();
|
||||
+ // emitChanges may alter m_cache and delete items
|
||||
+ QVarLengthArray<QPointer<QQmlDelegateModelAttached>> attachedObjects;
|
||||
+ attachedObjects.reserve(m_cache.length());
|
||||
+ for (const QQmlDelegateModelItem *cacheItem : qAsConst(m_cache))
|
||||
+ attachedObjects.append(cacheItem->attached);
|
||||
+
|
||||
+ for (const QPointer<QQmlDelegateModelAttached> &attached : qAsConst(attachedObjects)) {
|
||||
+ if (attached && attached->m_cacheItem)
|
||||
+ attached->emitChanges();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2707,20 +2712,24 @@ void QQmlDelegateModelAttached::emitChanges()
|
||||
m_previousGroups = m_cacheItem->groups;
|
||||
|
||||
int indexChanges = 0;
|
||||
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
|
||||
+ const int groupCount = m_cacheItem->metaType->groupCount;
|
||||
+ for (int i = 1; i < groupCount; ++i) {
|
||||
if (m_previousIndex[i] != m_currentIndex[i]) {
|
||||
m_previousIndex[i] = m_currentIndex[i];
|
||||
indexChanges |= (1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
+ // Don't access m_cacheItem anymore once we've started sending signals.
|
||||
+ // We don't own it and someone might delete it.
|
||||
+
|
||||
int notifierId = 0;
|
||||
const QMetaObject *meta = metaObject();
|
||||
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
|
||||
+ for (int i = 1; i < groupCount; ++i, ++notifierId) {
|
||||
if (groupChanges & (1 << i))
|
||||
QMetaObject::activate(this, meta, notifierId, nullptr);
|
||||
}
|
||||
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
|
||||
+ for (int i = 1; i < groupCount; ++i, ++notifierId) {
|
||||
if (indexChanges & (1 << i))
|
||||
QMetaObject::activate(this, meta, notifierId, nullptr);
|
||||
}
|
||||
diff --git a/tests/auto/qml/qqmldelegatemodel/data/deleteRace.qml b/tests/auto/qml/qqmldelegatemodel/data/deleteRace.qml
|
||||
new file mode 100644
|
||||
index 0000000000..23874970e7
|
||||
--- /dev/null
|
||||
+++ b/tests/auto/qml/qqmldelegatemodel/data/deleteRace.qml
|
||||
@@ -0,0 +1,50 @@
|
||||
+import QtQuick 2.15
|
||||
+import QtQml.Models 2.15
|
||||
+
|
||||
+Item {
|
||||
+ DelegateModel {
|
||||
+ id: delegateModel
|
||||
+ model: ListModel {
|
||||
+ id: sourceModel
|
||||
+
|
||||
+ ListElement { title: "foo" }
|
||||
+ ListElement { title: "bar" }
|
||||
+
|
||||
+ function clear() {
|
||||
+ if (count > 0)
|
||||
+ remove(0, count);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ groups: [
|
||||
+ DelegateModelGroup { name: "selectedItems" }
|
||||
+ ]
|
||||
+
|
||||
+ delegate: Text {
|
||||
+ height: DelegateModel.inSelectedItems ? implicitHeight * 2 : implicitHeight
|
||||
+ Component.onCompleted: {
|
||||
+ if (index === 0)
|
||||
+ DelegateModel.inSelectedItems = true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ Component.onCompleted: {
|
||||
+ items.create(0)
|
||||
+ items.create(1)
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ ListView {
|
||||
+ anchors.fill: parent
|
||||
+ model: delegateModel
|
||||
+ }
|
||||
+
|
||||
+ Timer {
|
||||
+ running: true
|
||||
+ interval: 10
|
||||
+ onTriggered: sourceModel.clear()
|
||||
+ }
|
||||
+
|
||||
+ property int count: delegateModel.items.count
|
||||
+}
|
||||
+
|
||||
diff --git a/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp b/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp
|
||||
index 1722447830..f473cff75f 100644
|
||||
--- a/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp
|
||||
+++ b/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp
|
||||
@@ -50,6 +50,7 @@ private slots:
|
||||
void qtbug_86017();
|
||||
void contextAccessedByHandler();
|
||||
void redrawUponColumnChange();
|
||||
+ void deleteRace();
|
||||
};
|
||||
|
||||
class AbstractItemModel : public QAbstractItemModel
|
||||
@@ -213,6 +214,17 @@ void tst_QQmlDelegateModel::redrawUponColumnChange()
|
||||
QCOMPARE(item->property("text").toString(), "Coconut");
|
||||
}
|
||||
|
||||
+void tst_QQmlDelegateModel::deleteRace()
|
||||
+{
|
||||
+ QQmlEngine engine;
|
||||
+ QQmlComponent c(&engine, testFileUrl("deleteRace.qml"));
|
||||
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
|
||||
+ QScopedPointer<QObject> o(c.create());
|
||||
+ QVERIFY(!o.isNull());
|
||||
+ QTRY_COMPARE(o->property("count").toInt(), 2);
|
||||
+ QTRY_COMPARE(o->property("count").toInt(), 0);
|
||||
+}
|
||||
+
|
||||
QTEST_MAIN(tst_QQmlDelegateModel)
|
||||
|
||||
#include "tst_qqmldelegatemodel.moc"
|
||||
--
|
||||
2.40.0
|
||||
|
@ -1,81 +0,0 @@
|
||||
From 11f5bc3d80c57ad2094ab2e8010955a1a0130feb Mon Sep 17 00:00:00 2001
|
||||
From: Volker Hilsheimer <volker.hilsheimer@qt.io>
|
||||
Date: Fri, 18 Nov 2022 14:20:20 +0100
|
||||
Subject: [PATCH 19/25] QQuickItem: Fix effective visibility for items without
|
||||
parent
|
||||
|
||||
Items are visible if they are children of a visible parent, and not
|
||||
explicitly hidden. The effectiveVisible member stores the state and is
|
||||
updated when conditions that impact the item visibility changes.
|
||||
|
||||
The old code returned true for items outside a visual hierarchy, which
|
||||
broke signal emission when items were removed from a parent, e.g.
|
||||
because the parent got destroyed. With this change, items removed from
|
||||
a visual hierarchy will emit the visibleChanged signal.
|
||||
|
||||
Note: QQuickItem initializes the effectiveVisible member to true, even
|
||||
if the item was created without parent item. Visual items are required
|
||||
to be added to a visual hierarchy via setParentItem. For this reason,
|
||||
newly created items never emit visibleChanged when they are added to
|
||||
a parent.
|
||||
|
||||
Adjust the QQuickItem::visible test - it creates an item hierarchy
|
||||
without window. Such items are never visible, so add a window and
|
||||
parent the test item hierarchy to the window's content item.
|
||||
|
||||
This fixes the expected failures in the tests. It does introduce an
|
||||
incompatibility with QGraphicsView and QGraphicsItem, which continue
|
||||
to return true from QGraphicsItem::isVisible for items that are not
|
||||
in an item hierarchy.
|
||||
|
||||
[ChangeLog][Qt Quick][QQuickItem] The visible property of Items without
|
||||
a parent now always returns false, and the visibleChanged signal gets
|
||||
emitted when the parent item of a visible item becomes null.
|
||||
|
||||
Fixes: QTBUG-108213
|
||||
Change-Id: If4b2947cefd1407853f0f29e6c3fdbd49fc9af65
|
||||
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
||||
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
|
||||
(cherry picked from commit d1b9a4cacfb966cf0a37983d8f8044f3aedf5de3)
|
||||
|
||||
CCBUG: 467909
|
||||
CCBUG: 396359
|
||||
---
|
||||
src/quick/items/qquickitem.cpp | 6 ++----
|
||||
tests/auto/quick/qquickitem/tst_qquickitem.cpp | 2 ++
|
||||
2 files changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
|
||||
index 708dc5fe5e..7236973216 100644
|
||||
--- a/src/quick/items/qquickitem.cpp
|
||||
+++ b/src/quick/items/qquickitem.cpp
|
||||
@@ -6082,10 +6082,8 @@ void QQuickItem::setEnabled(bool e)
|
||||
|
||||
bool QQuickItemPrivate::calcEffectiveVisible() const
|
||||
{
|
||||
- // XXX todo - Should the effective visible of an element with no parent just be the current
|
||||
- // effective visible? This would prevent pointless re-processing in the case of an element
|
||||
- // moving to/from a no-parent situation, but it is different from what graphics view does.
|
||||
- return explicitVisible && (!parentItem || QQuickItemPrivate::get(parentItem)->effectiveVisible);
|
||||
+ // An item is visible if it is a child of a visible parent, and not explicitly hidden.
|
||||
+ return explicitVisible && parentItem && QQuickItemPrivate::get(parentItem)->effectiveVisible;
|
||||
}
|
||||
|
||||
bool QQuickItemPrivate::setEffectiveVisibleRecur(bool newEffectiveVisible)
|
||||
diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
|
||||
index 42348d8dd1..34eefd85e6 100644
|
||||
--- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp
|
||||
+++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
|
||||
@@ -989,7 +989,9 @@ void tst_qquickitem::setParentItem()
|
||||
|
||||
void tst_qquickitem::visible()
|
||||
{
|
||||
+ QQuickWindow window;
|
||||
QQuickItem *root = new QQuickItem;
|
||||
+ root->setParentItem(window.contentItem());
|
||||
|
||||
QQuickItem *child1 = new QQuickItem;
|
||||
child1->setParentItem(root);
|
||||
--
|
||||
2.46.0
|
||||
|
@ -1,51 +0,0 @@
|
||||
From 9c27fd5c02dd4314192d142a9f2120be45748414 Mon Sep 17 00:00:00 2001
|
||||
From: Fushan Wen <qydwhotmail@gmail.com>
|
||||
Date: Fri, 21 Apr 2023 23:38:04 +0800
|
||||
Subject: [PATCH 20/25] Revert "QQuickItem: Fix effective visibility for items
|
||||
without parent"
|
||||
|
||||
This breaks applications that use QQmlPropertyList to store QQuickItem
|
||||
and don't set a parentItem for them.
|
||||
|
||||
Ref: https://github.com/musescore/MuseScore/issues/17276
|
||||
|
||||
This reverts commit 45c22a0221937682f4496801a495458a00f76d3a.
|
||||
---
|
||||
src/quick/items/qquickitem.cpp | 6 ++++--
|
||||
tests/auto/quick/qquickitem/tst_qquickitem.cpp | 2 --
|
||||
2 files changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
|
||||
index 7236973216..708dc5fe5e 100644
|
||||
--- a/src/quick/items/qquickitem.cpp
|
||||
+++ b/src/quick/items/qquickitem.cpp
|
||||
@@ -6082,8 +6082,10 @@ void QQuickItem::setEnabled(bool e)
|
||||
|
||||
bool QQuickItemPrivate::calcEffectiveVisible() const
|
||||
{
|
||||
- // An item is visible if it is a child of a visible parent, and not explicitly hidden.
|
||||
- return explicitVisible && parentItem && QQuickItemPrivate::get(parentItem)->effectiveVisible;
|
||||
+ // XXX todo - Should the effective visible of an element with no parent just be the current
|
||||
+ // effective visible? This would prevent pointless re-processing in the case of an element
|
||||
+ // moving to/from a no-parent situation, but it is different from what graphics view does.
|
||||
+ return explicitVisible && (!parentItem || QQuickItemPrivate::get(parentItem)->effectiveVisible);
|
||||
}
|
||||
|
||||
bool QQuickItemPrivate::setEffectiveVisibleRecur(bool newEffectiveVisible)
|
||||
diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
|
||||
index 34eefd85e6..42348d8dd1 100644
|
||||
--- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp
|
||||
+++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
|
||||
@@ -989,9 +989,7 @@ void tst_qquickitem::setParentItem()
|
||||
|
||||
void tst_qquickitem::visible()
|
||||
{
|
||||
- QQuickWindow window;
|
||||
QQuickItem *root = new QQuickItem;
|
||||
- root->setParentItem(window.contentItem());
|
||||
|
||||
QQuickItem *child1 = new QQuickItem;
|
||||
child1->setParentItem(root);
|
||||
--
|
||||
2.46.0
|
||||
|
@ -1,111 +0,0 @@
|
||||
From 9a1488c33d888e8d22905373599219b1d716aa8a Mon Sep 17 00:00:00 2001
|
||||
From: Volker Hilsheimer <volker.hilsheimer@qt.io>
|
||||
Date: Tue, 18 Apr 2023 22:05:36 +0200
|
||||
Subject: [PATCH 21/25] Accessibility: respect value in attached Accessible in
|
||||
controls
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
QQuickItemPrivate::accessibleRole is virtual and called by the framework
|
||||
to determine the role of an item. The default implementation checks and
|
||||
respects a possible Accessible attached object. However, subclasses that
|
||||
override the virtual don't, so the attached properties are ignored, and
|
||||
the class-specific implementation wins. This makes it impossible to
|
||||
change the role of e.g. a checkable button.
|
||||
|
||||
To fix that, move the code respecting the attached object into a non-
|
||||
virtual function that the framework calls instead, and only call the
|
||||
virtual member if there is no attached object, or if that object is not
|
||||
initialized with a role. Replace calls to the virtual from the
|
||||
framework with calls to the non-virtual wrapper.
|
||||
|
||||
Do this for both QQuickItem and for QQuickPopup, and adjust the logic
|
||||
in QQuickControl types that create an attached object and initialize
|
||||
it's role when accessibility becomes active. Use the non-overridable
|
||||
effective role value for that as well.
|
||||
|
||||
Add a test case, and to avoid any new framework calls to the virtual,
|
||||
make it private.
|
||||
|
||||
Fixes: QTBUG-110114
|
||||
Pick-to: 6.5 6.2
|
||||
Change-Id: Ia709cecbd181b6d8ee3297a4af60c1e7db9a2c51
|
||||
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
|
||||
Reviewed-by: Jan Arve Sæther <jan-arve.saether@qt.io>
|
||||
(cherry picked from commit 3c08d08ae2bbd449cc0579a1b3cb499383c7a60c)
|
||||
---
|
||||
src/quick/accessible/qaccessiblequickitem.cpp | 2 +-
|
||||
src/quick/items/qquickitem.cpp | 17 ++++++++++++-----
|
||||
src/quick/items/qquickitem_p.h | 3 +++
|
||||
3 files changed, 16 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/src/quick/accessible/qaccessiblequickitem.cpp b/src/quick/accessible/qaccessiblequickitem.cpp
|
||||
index a8df58d450..99e6eff7c3 100644
|
||||
--- a/src/quick/accessible/qaccessiblequickitem.cpp
|
||||
+++ b/src/quick/accessible/qaccessiblequickitem.cpp
|
||||
@@ -230,7 +230,7 @@ QAccessible::Role QAccessibleQuickItem::role() const
|
||||
|
||||
QAccessible::Role role = QAccessible::NoRole;
|
||||
if (item())
|
||||
- role = QQuickItemPrivate::get(item())->accessibleRole();
|
||||
+ role = QQuickItemPrivate::get(item())->effectiveAccessibleRole();
|
||||
if (role == QAccessible::NoRole) {
|
||||
if (qobject_cast<QQuickText*>(const_cast<QQuickItem *>(item())))
|
||||
role = QAccessible::StaticText;
|
||||
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
|
||||
index 708dc5fe5e..8b139cb539 100644
|
||||
--- a/src/quick/items/qquickitem.cpp
|
||||
+++ b/src/quick/items/qquickitem.cpp
|
||||
@@ -2401,7 +2401,7 @@ bool QQuickItemPrivate::canAcceptTabFocus(QQuickItem *item)
|
||||
return true;
|
||||
|
||||
#if QT_CONFIG(accessibility)
|
||||
- QAccessible::Role role = QQuickItemPrivate::get(item)->accessibleRole();
|
||||
+ QAccessible::Role role = QQuickItemPrivate::get(item)->effectiveAccessibleRole();
|
||||
if (role == QAccessible::EditableText || role == QAccessible::Table || role == QAccessible::List) {
|
||||
return true;
|
||||
} else if (role == QAccessible::ComboBox || role == QAccessible::SpinBox) {
|
||||
@@ -9010,13 +9010,20 @@ QQuickItemPrivate::ExtraData::ExtraData()
|
||||
|
||||
|
||||
#if QT_CONFIG(accessibility)
|
||||
-QAccessible::Role QQuickItemPrivate::accessibleRole() const
|
||||
+QAccessible::Role QQuickItemPrivate::effectiveAccessibleRole() const
|
||||
{
|
||||
Q_Q(const QQuickItem);
|
||||
- QQuickAccessibleAttached *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(qmlAttachedPropertiesObject<QQuickAccessibleAttached>(q, false));
|
||||
- if (accessibleAttached)
|
||||
- return accessibleAttached->role();
|
||||
+ auto *attached = qmlAttachedPropertiesObject<QQuickAccessibleAttached>(q, false);
|
||||
+ auto role = QAccessible::NoRole;
|
||||
+ if (auto *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(attached))
|
||||
+ role = accessibleAttached->role();
|
||||
+ if (role == QAccessible::NoRole)
|
||||
+ role = accessibleRole();
|
||||
+ return role;
|
||||
+}
|
||||
|
||||
+QAccessible::Role QQuickItemPrivate::accessibleRole() const
|
||||
+{
|
||||
return QAccessible::NoRole;
|
||||
}
|
||||
#endif
|
||||
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
|
||||
index ade8fb61f2..6f329bd119 100644
|
||||
--- a/src/quick/items/qquickitem_p.h
|
||||
+++ b/src/quick/items/qquickitem_p.h
|
||||
@@ -575,7 +575,10 @@ public:
|
||||
virtual void implicitHeightChanged();
|
||||
|
||||
#if QT_CONFIG(accessibility)
|
||||
+ QAccessible::Role effectiveAccessibleRole() const;
|
||||
+private:
|
||||
virtual QAccessible::Role accessibleRole() const;
|
||||
+public:
|
||||
#endif
|
||||
|
||||
void setImplicitAntialiasing(bool antialiasing);
|
||||
--
|
||||
2.46.0
|
||||
|
@ -1,111 +0,0 @@
|
||||
From 788c7ea1500dd6e82dd602fc51e5aa6f639bcf5e Mon Sep 17 00:00:00 2001
|
||||
From: Ulf Hermann <ulf.hermann@qt.io>
|
||||
Date: Mon, 10 Jul 2023 07:43:28 +0200
|
||||
Subject: [PATCH 22/25] QtQml: Clean up QQmlData ctor
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Initialize the "dummy" member even though we never use it. Static
|
||||
analyzers complain about it and we may appreciate it having a defined
|
||||
value in the future. Also, initialize other members inline where
|
||||
possible.
|
||||
|
||||
Coverity-Id: 415867
|
||||
Change-Id: Ie428eb3294d6363afe9d7ab2d2bed6e52df0b304
|
||||
Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
|
||||
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
||||
(cherry picked from commit 10985a568db8cfb4140140967f7d247627ec4350)
|
||||
|
||||
* asturmlechner 2023-08-12: Resolve conflicts with dev branch commits
|
||||
10985a568db8cfb4140140967f7d247627ec4350 and
|
||||
e5246cafffb93f69a49c133210390c253fcb71f2 and
|
||||
d3b3fef5a878d7fd53de6a9f9fff196a273930e3
|
||||
---
|
||||
src/qml/qml/qqmldata_p.h | 20 ++++++++++----------
|
||||
src/qml/qml/qqmlengine.cpp | 7 ++-----
|
||||
2 files changed, 12 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
|
||||
index ee31cb38d9..bb0adf9dfa 100644
|
||||
--- a/src/qml/qml/qqmldata_p.h
|
||||
+++ b/src/qml/qml/qqmldata_p.h
|
||||
@@ -187,7 +187,7 @@ public:
|
||||
private:
|
||||
void layout(QQmlNotifierEndpoint*);
|
||||
};
|
||||
- NotifyList *notifyList;
|
||||
+ NotifyList *notifyList = nullptr;
|
||||
|
||||
inline QQmlNotifierEndpoint *notify(int index);
|
||||
void addNotify(int index, QQmlNotifierEndpoint *);
|
||||
@@ -201,12 +201,12 @@ public:
|
||||
QQmlContextData *outerContext = nullptr;
|
||||
QQmlContextDataRef ownContext;
|
||||
|
||||
- QQmlAbstractBinding *bindings;
|
||||
- QQmlBoundSignal *signalHandlers;
|
||||
+ QQmlAbstractBinding *bindings = nullptr;
|
||||
+ QQmlBoundSignal *signalHandlers = nullptr;
|
||||
|
||||
// Linked list for QQmlContext::contextObjects
|
||||
- QQmlData *nextContextObject;
|
||||
- QQmlData**prevContextObject;
|
||||
+ QQmlData *nextContextObject = nullptr;
|
||||
+ QQmlData**prevContextObject = nullptr;
|
||||
|
||||
inline bool hasBindingBit(int) const;
|
||||
inline void setBindingBit(QObject *obj, int);
|
||||
@@ -216,10 +216,10 @@ public:
|
||||
inline void setPendingBindingBit(QObject *obj, int);
|
||||
inline void clearPendingBindingBit(int);
|
||||
|
||||
- quint16 lineNumber;
|
||||
- quint16 columnNumber;
|
||||
+ quint16 lineNumber = 0;
|
||||
+ quint16 columnNumber = 0;
|
||||
|
||||
- quint32 jsEngineId; // id of the engine that created the jsWrapper
|
||||
+ quint32 jsEngineId = 0; // id of the engine that created the jsWrapper
|
||||
|
||||
struct DeferredData {
|
||||
DeferredData();
|
||||
@@ -240,7 +240,7 @@ public:
|
||||
|
||||
QQmlPropertyCache *propertyCache;
|
||||
|
||||
- QQmlGuardImpl *guards;
|
||||
+ QQmlGuardImpl *guards = 0;
|
||||
|
||||
static QQmlData *get(const QObject *object, bool create = false) {
|
||||
QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
|
||||
@@ -289,7 +289,7 @@ public:
|
||||
|
||||
private:
|
||||
// For attachedProperties
|
||||
- mutable QQmlDataExtended *extendedData;
|
||||
+ mutable QQmlDataExtended *extendedData = nullptr;
|
||||
|
||||
Q_NEVER_INLINE static QQmlData *createQQmlData(QObjectPrivate *priv);
|
||||
Q_NEVER_INLINE static QQmlPropertyCache *createPropertyCache(QJSEngine *engine, QObject *object);
|
||||
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
|
||||
index 852a673ebd..86a2d2b45a 100644
|
||||
--- a/src/qml/qml/qqmlengine.cpp
|
||||
+++ b/src/qml/qml/qqmlengine.cpp
|
||||
@@ -725,11 +725,8 @@ void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
|
||||
QQmlData::QQmlData()
|
||||
: ownedByQml1(false), ownMemory(true), indestructible(true), explicitIndestructibleSet(false),
|
||||
hasTaintedV4Object(false), isQueuedForDeletion(false), rootObjectInCreation(false),
|
||||
- hasInterceptorMetaObject(false), hasVMEMetaObject(false), parentFrozen(false),
|
||||
- bindingBitsArraySize(InlineBindingArraySize), notifyList(nullptr),
|
||||
- bindings(nullptr), signalHandlers(nullptr), nextContextObject(nullptr), prevContextObject(nullptr),
|
||||
- lineNumber(0), columnNumber(0), jsEngineId(0),
|
||||
- propertyCache(nullptr), guards(nullptr), extendedData(nullptr)
|
||||
+ hasInterceptorMetaObject(false), hasVMEMetaObject(false), parentFrozen(false), dummy(0),
|
||||
+ bindingBitsArraySize(InlineBindingArraySize), propertyCache(nullptr)
|
||||
{
|
||||
memset(bindingBitsValue, 0, sizeof(bindingBitsValue));
|
||||
init();
|
||||
--
|
||||
2.46.0
|
||||
|
@ -1,277 +0,0 @@
|
||||
From d15877e074b5e7c0e61589168b5eaaced7e55bf4 Mon Sep 17 00:00:00 2001
|
||||
From: Ulf Hermann <ulf.hermann@qt.io>
|
||||
Date: Tue, 8 Aug 2023 14:54:01 +0200
|
||||
Subject: [PATCH 23/25] QML: Make notify list thread safe
|
||||
|
||||
We keep the notifyList itself alive until the QQmlData itself is
|
||||
deleted. This way any isSignalConnected() called while an
|
||||
intermediate dtor runs can safely access it. We use atomics to make the
|
||||
concurrent access to the pointer and the connection mask defined
|
||||
behavior. However, we never need anything but relaxed semantics when
|
||||
accessing it.
|
||||
|
||||
Pick-to: 5.15 6.2 6.5 6.6
|
||||
Fixes: QTBUG-105090
|
||||
Change-Id: I82537be86e5cc33c2a3d76ec639fcbac87eb45ad
|
||||
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
||||
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
|
||||
(cherry picked from commit 691956654c1acab356ce704c58602cc3a99fabc3)
|
||||
|
||||
* asturmlechner 2023-08-12: Resolve conflict with dev branch commit
|
||||
c249edb83fa67b3e5f711b28923397e66876182d which introduces a behavior
|
||||
change, so cannot be backported. Applied changes logically as if that
|
||||
commit never happened.
|
||||
---
|
||||
src/qml/qml/qqmldata_p.h | 66 ++++++++++++++++++-----------
|
||||
src/qml/qml/qqmlengine.cpp | 85 +++++++++++++++++++++++++-------------
|
||||
2 files changed, 99 insertions(+), 52 deletions(-)
|
||||
|
||||
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
|
||||
index bb0adf9dfa..187339169b 100644
|
||||
--- a/src/qml/qml/qqmldata_p.h
|
||||
+++ b/src/qml/qml/qqmldata_p.h
|
||||
@@ -176,24 +176,24 @@ public:
|
||||
};
|
||||
|
||||
struct NotifyList {
|
||||
- quint64 connectionMask;
|
||||
-
|
||||
- quint16 maximumTodoIndex;
|
||||
- quint16 notifiesSize;
|
||||
-
|
||||
- QQmlNotifierEndpoint *todo;
|
||||
- QQmlNotifierEndpoint**notifies;
|
||||
+ QAtomicInteger<quint64> connectionMask;
|
||||
+ QQmlNotifierEndpoint *todo = nullptr;
|
||||
+ QQmlNotifierEndpoint**notifies = nullptr;
|
||||
+ quint16 maximumTodoIndex = 0;
|
||||
+ quint16 notifiesSize = 0;
|
||||
void layout();
|
||||
private:
|
||||
void layout(QQmlNotifierEndpoint*);
|
||||
};
|
||||
- NotifyList *notifyList = nullptr;
|
||||
+ QAtomicPointer<NotifyList> notifyList;
|
||||
|
||||
- inline QQmlNotifierEndpoint *notify(int index);
|
||||
+ inline QQmlNotifierEndpoint *notify(int index) const;
|
||||
void addNotify(int index, QQmlNotifierEndpoint *);
|
||||
int endpointCount(int index);
|
||||
bool signalHasEndpoint(int index) const;
|
||||
- void disconnectNotifiers();
|
||||
+
|
||||
+ enum class DeleteNotifyList { Yes, No };
|
||||
+ void disconnectNotifiers(DeleteNotifyList doDelete);
|
||||
|
||||
// The context that created the C++ object
|
||||
QQmlContextData *context = nullptr;
|
||||
@@ -240,7 +240,7 @@ public:
|
||||
|
||||
QQmlPropertyCache *propertyCache;
|
||||
|
||||
- QQmlGuardImpl *guards = 0;
|
||||
+ QQmlGuardImpl *guards = nullptr;
|
||||
|
||||
static QQmlData *get(const QObject *object, bool create = false) {
|
||||
QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
|
||||
@@ -342,23 +342,31 @@ bool QQmlData::wasDeleted(const QObject *object)
|
||||
return ddata && ddata->isQueuedForDeletion;
|
||||
}
|
||||
|
||||
-QQmlNotifierEndpoint *QQmlData::notify(int index)
|
||||
+inline bool isIndexInConnectionMask(quint64 connectionMask, int index)
|
||||
+{
|
||||
+ return connectionMask & (1ULL << quint64(index % 64));
|
||||
+}
|
||||
+
|
||||
+QQmlNotifierEndpoint *QQmlData::notify(int index) const
|
||||
{
|
||||
+ // Can only happen on "home" thread. We apply relaxed semantics when loading the atomics.
|
||||
+
|
||||
Q_ASSERT(index <= 0xFFFF);
|
||||
|
||||
- if (!notifyList || !(notifyList->connectionMask & (1ULL << quint64(index % 64)))) {
|
||||
+ NotifyList *list = notifyList.loadRelaxed();
|
||||
+ if (!list || !isIndexInConnectionMask(list->connectionMask.loadRelaxed(), index))
|
||||
return nullptr;
|
||||
- } else if (index < notifyList->notifiesSize) {
|
||||
- return notifyList->notifies[index];
|
||||
- } else if (index <= notifyList->maximumTodoIndex) {
|
||||
- notifyList->layout();
|
||||
- }
|
||||
|
||||
- if (index < notifyList->notifiesSize) {
|
||||
- return notifyList->notifies[index];
|
||||
- } else {
|
||||
- return nullptr;
|
||||
+ if (index < list->notifiesSize)
|
||||
+ return list->notifies[index];
|
||||
+
|
||||
+ if (index <= list->maximumTodoIndex) {
|
||||
+ list->layout();
|
||||
+ if (index < list->notifiesSize)
|
||||
+ return list->notifies[index];
|
||||
}
|
||||
+
|
||||
+ return nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -367,7 +375,19 @@ QQmlNotifierEndpoint *QQmlData::notify(int index)
|
||||
*/
|
||||
inline bool QQmlData::signalHasEndpoint(int index) const
|
||||
{
|
||||
- return notifyList && (notifyList->connectionMask & (1ULL << quint64(index % 64)));
|
||||
+ // This can be called from any thread.
|
||||
+ // We still use relaxed semantics. If we're on a thread different from the "home" thread
|
||||
+ // of the QQmlData, two interesting things might happen:
|
||||
+ //
|
||||
+ // 1. The list might go away while we hold it. In that case we are dealing with an object whose
|
||||
+ // QObject dtor is being executed concurrently. This is UB already without the notify lists.
|
||||
+ // Therefore, we don't need to consider it.
|
||||
+ // 2. The connectionMask may be amended or zeroed while we are looking at it. In that case
|
||||
+ // we "misreport" the endpoint. Since ordering of events across threads is inherently
|
||||
+ // nondeterministic, either result is correct in that case. We can accept it.
|
||||
+
|
||||
+ NotifyList *list = notifyList.loadRelaxed();
|
||||
+ return list && isIndexInConnectionMask(list->connectionMask.loadRelaxed(), index);
|
||||
}
|
||||
|
||||
bool QQmlData::hasBindingBit(int coreIndex) const
|
||||
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
|
||||
index 86a2d2b45a..d6b2711c2d 100644
|
||||
--- a/src/qml/qml/qqmlengine.cpp
|
||||
+++ b/src/qml/qml/qqmlengine.cpp
|
||||
@@ -718,7 +718,7 @@ void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
|
||||
// Disconnect the notifiers now - during object destruction this would be too late, since
|
||||
// the disconnect call wouldn't be able to call disconnectNotify(), as it isn't possible to
|
||||
// get the metaobject anymore.
|
||||
- d->disconnectNotifiers();
|
||||
+ d->disconnectNotifiers(QQmlData::DeleteNotifyList::No);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -786,7 +786,10 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in
|
||||
// QQmlEngine to emit signals from a different thread. These signals are then automatically
|
||||
// marshalled back onto the QObject's thread and handled by QML from there. This is tested
|
||||
// by the qqmlecmascript::threadSignal() autotest.
|
||||
- if (!ddata->notifyList)
|
||||
+
|
||||
+ // Relaxed semantics here. If we're on a different thread we might schedule a useless event,
|
||||
+ // but that should be rare.
|
||||
+ if (!ddata->notifyList.loadRelaxed())
|
||||
return;
|
||||
|
||||
auto objectThreadData = QObjectPrivate::get(object)->threadData.loadRelaxed();
|
||||
@@ -1832,49 +1835,73 @@ void QQmlData::releaseDeferredData()
|
||||
|
||||
void QQmlData::addNotify(int index, QQmlNotifierEndpoint *endpoint)
|
||||
{
|
||||
- if (!notifyList) {
|
||||
- notifyList = (NotifyList *)malloc(sizeof(NotifyList));
|
||||
- notifyList->connectionMask = 0;
|
||||
- notifyList->maximumTodoIndex = 0;
|
||||
- notifyList->notifiesSize = 0;
|
||||
- notifyList->todo = nullptr;
|
||||
- notifyList->notifies = nullptr;
|
||||
+ // Can only happen on "home" thread. We apply relaxed semantics when loading the atomics.
|
||||
+
|
||||
+ NotifyList *list = notifyList.loadRelaxed();
|
||||
+
|
||||
+ if (!list) {
|
||||
+ list = new NotifyList;
|
||||
+ // We don't really care when this change takes effect on other threads. The notifyList can
|
||||
+ // only become non-null once in the life time of a QQmlData. It becomes null again when the
|
||||
+ // underlying QObject is deleted. At that point any interaction with the QQmlData is UB
|
||||
+ // anyway. So, for all intents and purposese, the list becomes non-null once and then stays
|
||||
+ // non-null "forever". We can apply relaxed semantics.
|
||||
+ notifyList.storeRelaxed(list);
|
||||
}
|
||||
|
||||
Q_ASSERT(!endpoint->isConnected());
|
||||
|
||||
index = qMin(index, 0xFFFF - 1);
|
||||
- notifyList->connectionMask |= (1ULL << quint64(index % 64));
|
||||
|
||||
- if (index < notifyList->notifiesSize) {
|
||||
+ // Likewise, we don't really care _when_ the change in the connectionMask is propagated to other
|
||||
+ // threads. Cross-thread event ordering is inherently nondeterministic. Therefore, when querying
|
||||
+ // the conenctionMask in the presence of concurrent modification, any result is correct.
|
||||
+ list->connectionMask.storeRelaxed(
|
||||
+ list->connectionMask.loadRelaxed() | (1ULL << quint64(index % 64)));
|
||||
|
||||
- endpoint->next = notifyList->notifies[index];
|
||||
+ if (index < list->notifiesSize) {
|
||||
+ endpoint->next = list->notifies[index];
|
||||
if (endpoint->next) endpoint->next->prev = &endpoint->next;
|
||||
- endpoint->prev = ¬ifyList->notifies[index];
|
||||
- notifyList->notifies[index] = endpoint;
|
||||
-
|
||||
+ endpoint->prev = &list->notifies[index];
|
||||
+ list->notifies[index] = endpoint;
|
||||
} else {
|
||||
- notifyList->maximumTodoIndex = qMax(int(notifyList->maximumTodoIndex), index);
|
||||
+ list->maximumTodoIndex = qMax(int(list->maximumTodoIndex), index);
|
||||
|
||||
- endpoint->next = notifyList->todo;
|
||||
+ endpoint->next = list->todo;
|
||||
if (endpoint->next) endpoint->next->prev = &endpoint->next;
|
||||
- endpoint->prev = ¬ifyList->todo;
|
||||
- notifyList->todo = endpoint;
|
||||
+ endpoint->prev = &list->todo;
|
||||
+ list->todo = endpoint;
|
||||
}
|
||||
}
|
||||
|
||||
-void QQmlData::disconnectNotifiers()
|
||||
+void QQmlData::disconnectNotifiers(QQmlData::DeleteNotifyList doDelete)
|
||||
{
|
||||
- if (notifyList) {
|
||||
- while (notifyList->todo)
|
||||
- notifyList->todo->disconnect();
|
||||
- for (int ii = 0; ii < notifyList->notifiesSize; ++ii) {
|
||||
- while (QQmlNotifierEndpoint *ep = notifyList->notifies[ii])
|
||||
+ // Can only happen on "home" thread. We apply relaxed semantics when loading the atomics.
|
||||
+ if (NotifyList *list = notifyList.loadRelaxed()) {
|
||||
+ while (QQmlNotifierEndpoint *todo = list->todo)
|
||||
+ todo->disconnect();
|
||||
+ for (int ii = 0; ii < list->notifiesSize; ++ii) {
|
||||
+ while (QQmlNotifierEndpoint *ep = list->notifies[ii])
|
||||
ep->disconnect();
|
||||
}
|
||||
- free(notifyList->notifies);
|
||||
- free(notifyList);
|
||||
- notifyList = nullptr;
|
||||
+ free(list->notifies);
|
||||
+
|
||||
+ if (doDelete == DeleteNotifyList::Yes) {
|
||||
+ // We can only get here from QQmlData::destroyed(), and that can only come from the
|
||||
+ // the QObject dtor. If you're still sending signals at that point you have UB already
|
||||
+ // without any threads. Therefore, it's enough to apply relaxed semantics.
|
||||
+ notifyList.storeRelaxed(nullptr);
|
||||
+ delete list;
|
||||
+ } else {
|
||||
+ // We can use relaxed semantics here. The worst thing that can happen is that some
|
||||
+ // signal is falsely reported as connected. Signal connectedness across threads
|
||||
+ // is not quite deterministic anyway.
|
||||
+ list->connectionMask.storeRelaxed(0);
|
||||
+ list->maximumTodoIndex = 0;
|
||||
+ list->notifiesSize = 0;
|
||||
+ list->notifies = nullptr;
|
||||
+
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1958,7 +1985,7 @@ void QQmlData::destroyed(QObject *object)
|
||||
guard->objectDestroyed(object);
|
||||
}
|
||||
|
||||
- disconnectNotifiers();
|
||||
+ disconnectNotifiers(DeleteNotifyList::Yes);
|
||||
|
||||
if (extendedData)
|
||||
delete extendedData;
|
||||
--
|
||||
2.46.0
|
||||
|
@ -1,54 +0,0 @@
|
||||
From 83cac09d86872edaa6fd4779597d6ba0bc4d2a8e Mon Sep 17 00:00:00 2001
|
||||
From: Ulf Hermann <ulf.hermann@qt.io>
|
||||
Date: Wed, 8 Feb 2023 12:14:21 +0100
|
||||
Subject: [PATCH 24/25] QML: Fortify qmlExecuteDeferred some more
|
||||
|
||||
I don't know how to trigger this, but a recent crash report from the CI
|
||||
shows that we can get there without a valid engine.
|
||||
|
||||
Pick-to: 6.5
|
||||
Change-Id: I9f17894da82b8e7eab88181c96dfa8eaf7795523
|
||||
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
||||
(cherry picked from commit f69b6f0940b178b46ecbaa5f0b4956ac44e8379e)
|
||||
---
|
||||
src/qml/qml/qqmlengine.cpp | 21 +++++++++++++--------
|
||||
1 file changed, 13 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
|
||||
index d6b2711c2d..5f3367e4d2 100644
|
||||
--- a/src/qml/qml/qqmlengine.cpp
|
||||
+++ b/src/qml/qml/qqmlengine.cpp
|
||||
@@ -1588,17 +1588,22 @@ void qmlExecuteDeferred(QObject *object)
|
||||
{
|
||||
QQmlData *data = QQmlData::get(object);
|
||||
|
||||
- if (data && !data->deferredData.isEmpty() && !data->wasDeleted(object)) {
|
||||
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine);
|
||||
+ if (!data
|
||||
+ || !data->context
|
||||
+ || !data->context->engine
|
||||
+ || data->deferredData.isEmpty()
|
||||
+ || data->wasDeleted(object)) {
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
- QQmlComponentPrivate::DeferredState state;
|
||||
- QQmlComponentPrivate::beginDeferred(ep, object, &state);
|
||||
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine);
|
||||
+ QQmlComponentPrivate::DeferredState state;
|
||||
+ QQmlComponentPrivate::beginDeferred(ep, object, &state);
|
||||
|
||||
- // Release the reference for the deferral action (we still have one from construction)
|
||||
- data->releaseDeferredData();
|
||||
+ // Release the reference for the deferral action (we still have one from construction)
|
||||
+ data->releaseDeferredData();
|
||||
|
||||
- QQmlComponentPrivate::completeDeferred(ep, &state);
|
||||
- }
|
||||
+ QQmlComponentPrivate::completeDeferred(ep, &state);
|
||||
}
|
||||
|
||||
QQmlContext *qmlContext(const QObject *obj)
|
||||
--
|
||||
2.46.0
|
||||
|
@ -1,52 +0,0 @@
|
||||
From 310c124dac82d711ab15309a9cb0b9d95db9ea8f Mon Sep 17 00:00:00 2001
|
||||
From: Antonio Napolitano <anton@polit.no>
|
||||
Date: Sat, 30 Dec 2023 19:11:32 +0100
|
||||
Subject: [PATCH 25/25] masm: Don't crash on failed MADV_DONTNEED on Linux
|
||||
|
||||
The application could call mlockall(MCL_CURRENT|MCL_FUTURE) to lock all
|
||||
its memory for performance reasons, causing the madvise call to fail.
|
||||
There's no need to crash. Instead, manually zero-out the memory when
|
||||
decommitting.
|
||||
|
||||
Fixes: QTBUG-120450
|
||||
Pick-to: 5.15 6.2 6.5 6.6 6.7
|
||||
Change-Id: I6f1a8968853cc5e61561371bd2a435a686eaf0e4
|
||||
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
||||
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
|
||||
(cherry picked from commit 524d260c5c135d193e06350e48357444ddb13ddb)
|
||||
---
|
||||
src/3rdparty/masm/wtf/OSAllocatorPosix.cpp | 11 +++++------
|
||||
1 file changed, 5 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp b/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp
|
||||
index b5c5f6a2b0..1a3d3cdf97 100644
|
||||
--- a/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp
|
||||
+++ b/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp
|
||||
@@ -112,10 +112,7 @@ void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable,
|
||||
if (result == MAP_FAILED)
|
||||
CRASH();
|
||||
|
||||
- while (madvise(result, bytes, MADV_DONTNEED)) {
|
||||
- if (errno != EAGAIN)
|
||||
- CRASH();
|
||||
- }
|
||||
+ while (madvise(result, bytes, MADV_DONTNEED) == -1 && errno == EAGAIN) { }
|
||||
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
@@ -248,8 +245,10 @@ void OSAllocator::decommit(void* address, size_t bytes)
|
||||
mmap(address, bytes, PROT_NONE, MAP_FIXED | MAP_LAZY | MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
#elif OS(LINUX)
|
||||
while (madvise(address, bytes, MADV_DONTNEED)) {
|
||||
- if (errno != EAGAIN)
|
||||
- CRASH();
|
||||
+ if (errno != EAGAIN) {
|
||||
+ memset(address, 0, bytes); // We rely on madvise to zero-out the memory
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
if (mprotect(address, bytes, PROT_NONE))
|
||||
CRASH();
|
||||
--
|
||||
2.46.0
|
||||
|
@ -0,0 +1,44 @@
|
||||
From e2bdde18d9758efdc6a0d7d106aad56995df1271 Mon Sep 17 00:00:00 2001
|
||||
From: Ulf Hermann <ulf.hermann@qt.io>
|
||||
Date: Wed, 15 Mar 2023 08:59:43 +0100
|
||||
Subject: [PATCH] JIT: Add missing {STORE|LOAD}_ACC() to CreateCallContext
|
||||
|
||||
We cannot assume anything about the accumulator register after calling
|
||||
PushCallContext::call(). Also add a note about not needing to re-load
|
||||
the accumulator on ThrowException.
|
||||
|
||||
Pick-to: 6.5 6.2 5.15
|
||||
Fixes: QTBUG-111935
|
||||
Change-Id: I7196585e1d2697c215f4fe87d8d7ac9b98b622a3
|
||||
---
|
||||
src/qml/jit/qv4baselinejit.cpp | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp
|
||||
index 14e183adb8..1d65169dce 100644
|
||||
--- a/src/qml/jit/qv4baselinejit.cpp
|
||||
+++ b/src/qml/jit/qv4baselinejit.cpp
|
||||
@@ -506,6 +506,8 @@ void BaselineJIT::generate_ThrowException()
|
||||
as->passEngineAsArg(0);
|
||||
BASELINEJIT_GENERATE_RUNTIME_CALL(ThrowException, CallResultDestination::Ignore);
|
||||
as->gotoCatchException();
|
||||
+
|
||||
+ // LOAD_ACC(); <- not needed here since it would be unreachable.
|
||||
}
|
||||
|
||||
void BaselineJIT::generate_GetException() { as->getException(); }
|
||||
@@ -513,9 +515,11 @@ void BaselineJIT::generate_SetException() { as->setException(); }
|
||||
|
||||
void BaselineJIT::generate_CreateCallContext()
|
||||
{
|
||||
+ STORE_ACC();
|
||||
as->prepareCallWithArgCount(1);
|
||||
as->passCppFrameAsArg(0);
|
||||
BASELINEJIT_GENERATE_RUNTIME_CALL(PushCallContext, CallResultDestination::Ignore);
|
||||
+ LOAD_ACC();
|
||||
}
|
||||
|
||||
void BaselineJIT::generate_PushCatchContext(int index, int name) { as->pushCatchContext(index, name); }
|
||||
--
|
||||
2.39.2
|
||||
|
@ -0,0 +1,12 @@
|
||||
diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro
|
||||
index 621e8bb4..24ea2201 100644
|
||||
--- a/tests/auto/qml/qml.pro
|
||||
+++ b/tests/auto/qml/qml.pro
|
||||
@@ -25,7 +25,6 @@ PUBLICTESTS += \
|
||||
qqmlmoduleplugin \
|
||||
qqmlnotifier \
|
||||
qqmlqt \
|
||||
- qqmlxmlhttprequest \
|
||||
qqmlpromise \
|
||||
qtqmlmodules \
|
||||
qquickfolderlistmodel \
|
Loading…
Reference in new issue