public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/qt6-qtdeclarative] rawhide: Upstream backport:
@ 2026-09-11 10:34 Jan Grulich
0 siblings, 0 replies; 2+ messages in thread
From: Jan Grulich @ 2026-09-11 10:34 UTC (permalink / raw)
To: git-commits
A new commit has been pushed.
Repo : rpms/qt6-qtdeclarative
Branch : rawhide
Commit : 05d82bbddd43586d414b848733f91e2577344b97
Author : Jan Grulich <jgrulich@redhat.com>
Date : 2026-09-11T12:33:52+02:00
Stats : +336/-1 in 2 file(s)
URL : https://src.fedoraproject.org/rpms/qt6-qtdeclarative/c/05d82bbddd43586d414b848733f91e2577344b97?branch=rawhide
Log:
Upstream backport:
QML Engine: correctly compare composites when multiple engines are used
---
diff --git a/qt6-qtdeclarative.spec b/qt6-qtdeclarative.spec
index e2c9768..aadbe9a 100644
--- a/qt6-qtdeclarative.spec
+++ b/qt6-qtdeclarative.spec
@@ -16,7 +16,7 @@
Summary: Qt6 - QtDeclarative component
Name: qt6-%{qt_module}
Version: 6.11.2
-Release: 1%{?dist}
+Release: 2%{?dist}
License: LGPL-3.0-only OR GPL-3.0-only WITH Qt-GPL-exception-1.0
Url: http://www.qt.io
@@ -34,6 +34,7 @@ Source0: https://download.qt.io/official_releases/qt/%{majmin}/%{version}/submod
Source5: qv4global_p-multilib.h
## upstream patches
+Patch0: qtdeclarative-qml-engine-correctly-compare-composites-with-multi-engines.patch
## upstreamable patches
@@ -759,6 +760,10 @@ make check -k -C tests ||:
%endif
%changelog
+* Fri Sep 11 2026 Jan Grulich <jgrulich@redhat.com> - 6.11.2-2
+- Upstream backport:
+ - QML Engine: correctly compare composites when multiple engines are used
+
* Fri Aug 21 2026 Jan Grulich <jgrulich@redhat.com> - 6.11.2-1
- 6.11.2
diff --git a/qtdeclarative-qml-engine-correctly-compare-composites-with-multi-engines.patch b/qtdeclarative-qml-engine-correctly-compare-composites-with-multi-engines.patch
new file mode 100644
index 0000000..e5d01bd
--- /dev/null
+++ b/qtdeclarative-qml-engine-correctly-compare-composites-with-multi-engines.patch
@@ -0,0 +1,330 @@
+From 8b8c30429419a3b9f0bd74fd5fb0066c851ae623 Mon Sep 17 00:00:00 2001
+From: Fabian Kosmale <fabian.kosmale@qt.io>
+Date: Mon, 31 Aug 2026 16:54:58 +0200
+Subject: [PATCH] QML engine: Correctly compare composites when multiple engines are used
+
+Since 6.11, we allow multiple types to be active for the same URL.
+While we converted multiple places to handle this, we missed adjusting
+the property validator. There, we just picked the last inserted property
+cache, which can lead to validation failures.
+
+Fix this by adding a fallback path which checks all potential matches
+when the initial lookup would yield an error.
+
+The same kind of check is also needed in qmlobject_can_qml_cast.
+
+Amends 9cc23ca91c404f24fff3c36e8c9425ae674f341d.
+
+Change compared to 6.12:
+Dropped the isComposite check, which doesn't exist there. That causes
+one potential extra unneeded lock acquisition, but only in a case
+where'd we get an error anyway.
+
+Fixes: QTBUG-149607
+Change-Id: Ibd0df2325807e75b23056ebc0bacdfe877b002f3
+Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
+(cherry picked from commit 94a76ed58629932f6d689c48ecf8d3132188923b)
+Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
+(cherry picked from commit 8c23f65ec4889f9ff7f609002a129698796de2b8)
+---
+
+diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp
+index 3e11b86..e4d94e4 100644
+--- a/src/qml/qml/qqmlglobal.cpp
++++ b/src/qml/qml/qqmlglobal.cpp
+@@ -1112,9 +1112,9 @@
+
+ // A non-composite type will always have a metaobject.
+ const QMetaObject *typeMetaObject = type.metaObject();
+- const QQmlPropertyCache::ConstPtr typePropertyCache = typeMetaObject
+- ? QQmlPropertyCache::ConstPtr()
+- : QQmlMetaType::findPropertyCacheInCompositeTypes(type.typeId());
++ QVarLengthArray<QQmlPropertyCache::ConstPtr, 4> allPropertyCacheCandidates =
++ typeMetaObject ? QVarLengthArray<QQmlPropertyCache::ConstPtr, 4>{}
++ : QQmlMetaType::rawCompositePropertyCachesForType(type.typeId());
+
+ if (const QQmlData *ddata = ddata_for_cast(object)) {
+ for (const QQmlPropertyCache *propertyCache = ddata->propertyCache.data(); propertyCache;
+@@ -1134,17 +1134,17 @@
+ // property caches to be unrelated but the types still convertible.
+ // Multiple property caches can hold the same metaobject, for example for
+ // versions of non-composite types.
+- if (propertyCache == typePropertyCache.data())
++ if (allPropertyCacheCandidates.contains(propertyCache))
+ return true;
+ }
+ }
+ }
+
+- // If nothing else works, we have to create the metaobjects.
++ // If nothing else works, we have to create the metaobjects (if we can).
++ if (!typeMetaObject && !allPropertyCacheCandidates.isEmpty())
++ typeMetaObject = allPropertyCacheCandidates.first()->createMetaObject();
+
+- return object->metaObject()->inherits(typeMetaObject
+- ? typeMetaObject
+- : (typePropertyCache ? typePropertyCache->createMetaObject() : nullptr));
++ return object->metaObject()->inherits(typeMetaObject);
+ }
+
+ QT_END_NAMESPACE
+diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
+index 173c21d..1703c99 100644
+--- a/src/qml/qml/qqmlmetatype.cpp
++++ b/src/qml/qml/qqmlmetatype.cpp
+@@ -1490,6 +1490,20 @@
+ /*!
+ * \internal
+ *
++ * Returns all candidate property caches for a composite
++ * metatype instead of only the last inserted one.
++ * compare rawPropertyCacheForType (which handles however also non-composites)
++ */
++QVarLengthArray<QQmlPropertyCache::ConstPtr, 4>
++QQmlMetaType::rawCompositePropertyCachesForType(QMetaType metaType)
++{
++ const QQmlMetaTypeDataPtr data;
++ return data->findPropertyCachesInCompositeTypes(metaType);
++}
++
++/*!
++ * \internal
++ *
+ * Look up by QQmlType and version. We only fall back to lookup by metaobject if the type
+ * has no revisiononed attributes here. Unspecified versions are interpreted as "any".
+ */
+diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
+index 62b6cba..040a42d 100644
+--- a/src/qml/qml/qqmlmetatype_p.h
++++ b/src/qml/qml/qqmlmetatype_p.h
+@@ -23,6 +23,7 @@
+ #include <private/qtqmlglobal_p.h>
+
+ #include <QtCore/qtyperevision.h>
++#include <QtCore/qvarlengtharray.h>
+
+ QT_BEGIN_NAMESPACE
+
+@@ -171,6 +172,10 @@
+ static QQmlPropertyCache::ConstPtr rawPropertyCacheForType(
+ QMetaType metaType, QTypeRevision version);
+
++ // All property caches for a composite metatype, which may map to more than one of them.
++ static QVarLengthArray<QQmlPropertyCache::ConstPtr, 4> rawCompositePropertyCachesForType(
++ QMetaType metaType);
++
+ static bool canConvert(QObject *o, QMetaType metaType);
+ static bool canConvert(const QQmlPropertyCache::ConstPtr &from, QMetaType metaType);
+
+diff --git a/src/qml/qml/qqmlmetatypedata.cpp b/src/qml/qml/qqmlmetatypedata.cpp
+index e72a3a9..41d7d8c 100644
+--- a/src/qml/qml/qqmlmetatypedata.cpp
++++ b/src/qml/qml/qqmlmetatypedata.cpp
+@@ -257,6 +257,18 @@
+ : propertyCacheForPotentialInlineComponentType(t, iter);
+ }
+
++QVarLengthArray<QQmlPropertyCache::ConstPtr, 4>
++QQmlMetaTypeData::findPropertyCachesInCompositeTypes(QMetaType t) const
++{
++ QVarLengthArray<QQmlPropertyCache::ConstPtr, 4> result;
++ const auto [begin, end] = compositeTypes.equal_range(t.iface());
++ for (auto iter = begin; iter != end; ++iter) {
++ if (auto cache = propertyCacheForPotentialInlineComponentType(t, iter))
++ result.append(std::move(cache));
++ }
++ return result;
++}
++
+ void QQmlMetaTypeData::clearCompositeTypes()
+ {
+ // Unregister all remaining composite types.
+diff --git a/src/qml/qml/qqmlmetatypedata_p.h b/src/qml/qml/qqmlmetatypedata_p.h
+index ce13c40..95c60a1 100644
+--- a/src/qml/qml/qqmlmetatypedata_p.h
++++ b/src/qml/qml/qqmlmetatypedata_p.h
+@@ -23,6 +23,7 @@
+ #include <private/qqmlvaluetype_p.h>
+
+ #include <QtCore/qset.h>
++#include <QtCore/qvarlengtharray.h>
+ #include <QtCore/qvector.h>
+
+ QT_BEGIN_NAMESPACE
+@@ -119,6 +120,10 @@
+ QQmlPropertyCache::ConstPtr propertyCache(const QQmlType &type, QTypeRevision version);
+ QQmlPropertyCache::ConstPtr findPropertyCacheInCompositeTypes(QMetaType t) const;
+
++ // Same, but returns all matches rather than only the last inserted one.
++ QVarLengthArray<QQmlPropertyCache::ConstPtr, 4> findPropertyCachesInCompositeTypes(
++ QMetaType t) const;
++
+ static QQmlPropertyCache::ConstPtr propertyCacheForPotentialInlineComponentType(
+ QMetaType t, const QQmlMetaTypeData::CompositeTypes::const_iterator &iter);
+
+diff --git a/src/qml/qml/qqmlpropertyvalidator.cpp b/src/qml/qml/qqmlpropertyvalidator.cpp
+index c252f47..1acbb22 100644
+--- a/src/qml/qml/qqmlpropertyvalidator.cpp
++++ b/src/qml/qml/qqmlpropertyvalidator.cpp
+@@ -2,6 +2,7 @@
+ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+ // Qt-Security score:significant
+
++#include "qqmlmetatype_p.h"
+ #include "qqmlpropertyvalidator_p.h"
+
+ #include <private/qqmlcustomparser_p.h>
+@@ -781,10 +782,29 @@
+ // Will be true if the assigned type inherits propertyMetaObject
+ // Determine isAssignable value
+ bool isAssignable = false;
+- QQmlPropertyCache::ConstPtr c = propertyCaches.at(binding->value.objectIndex);
+- while (c && !isAssignable) {
+- isAssignable |= c == propertyMetaObject;
+- c = c->parent();
++ QQmlPropertyCache::ConstPtr source = propertyCaches.at(binding->value.objectIndex);
++
++ const auto inheritsFrom = [&](const QQmlPropertyCache::ConstPtr &target) {
++ for (QQmlPropertyCache::ConstPtr c = source; c; c = c->parent()) {
++ if (c == target)
++ return true;
++ }
++ return false;
++ };
++
++ isAssignable = inheritsFrom(propertyMetaObject);
++
++ if (!isAssignable) {
++ // A single (composite) metatype can map to multiple property caches when
++ // there are multiple engines; rawPropertyCacheForType only returns one of
++ // them. For non-composite types this yields an empty list and is a no-op.
++ const auto candidates = QQmlMetaType::rawCompositePropertyCachesForType(propType);
++ for (const auto &candidate : candidates) {
++ if (inheritsFrom(candidate)) {
++ isAssignable = true;
++ break;
++ }
++ }
+ }
+
+ if (!isAssignable) {
+diff --git a/tests/auto/qml/qqmllanguage/data/canQmlCastMultiEngine/Foo.qml b/tests/auto/qml/qqmllanguage/data/canQmlCastMultiEngine/Foo.qml
+new file mode 100644
+index 0000000..8fc36a4
+--- /dev/null
++++ b/tests/auto/qml/qqmllanguage/data/canQmlCastMultiEngine/Foo.qml
+@@ -0,0 +1,3 @@
++import QtQml
++
++QtObject {}
+diff --git a/tests/auto/qml/qqmllanguage/data/canQmlCastMultiEngine/Main.qml b/tests/auto/qml/qqmllanguage/data/canQmlCastMultiEngine/Main.qml
+new file mode 100644
+index 0000000..1470151
+--- /dev/null
++++ b/tests/auto/qml/qqmllanguage/data/canQmlCastMultiEngine/Main.qml
+@@ -0,0 +1,9 @@
++import QtQml
++
++QtObject {
++ property Foo theFoo: Foo {}
++
++ function check(foo: Foo) : bool {
++ return foo !== null;
++ }
++}
+diff --git a/tests/auto/qml/qqmllanguage/data/propertyValidatorMultiEngine/Consumer1.qml b/tests/auto/qml/qqmllanguage/data/propertyValidatorMultiEngine/Consumer1.qml
+new file mode 100644
+index 0000000..80de08e
+--- /dev/null
++++ b/tests/auto/qml/qqmllanguage/data/propertyValidatorMultiEngine/Consumer1.qml
+@@ -0,0 +1,5 @@
++import QtQml
++
++QtObject {
++ property Foo f: Foo {}
++}
+diff --git a/tests/auto/qml/qqmllanguage/data/propertyValidatorMultiEngine/Consumer2.qml b/tests/auto/qml/qqmllanguage/data/propertyValidatorMultiEngine/Consumer2.qml
+new file mode 100644
+index 0000000..80de08e
+--- /dev/null
++++ b/tests/auto/qml/qqmllanguage/data/propertyValidatorMultiEngine/Consumer2.qml
+@@ -0,0 +1,5 @@
++import QtQml
++
++QtObject {
++ property Foo f: Foo {}
++}
+diff --git a/tests/auto/qml/qqmllanguage/data/propertyValidatorMultiEngine/Foo.qml b/tests/auto/qml/qqmllanguage/data/propertyValidatorMultiEngine/Foo.qml
+new file mode 100644
+index 0000000..8fc36a4
+--- /dev/null
++++ b/tests/auto/qml/qqmllanguage/data/propertyValidatorMultiEngine/Foo.qml
+@@ -0,0 +1,3 @@
++import QtQml
++
++QtObject {}
+diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+index c683aa1..0af0f34 100644
+--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
++++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+@@ -298,6 +298,8 @@
+ void instanceof();
+ void instanceofMultiEngine();
+ void instanceofMultiEngineInlineComponent();
++ void propertyValidatorMultiEngine();
++ void canQmlCastMultiEngine();
+
+ void concurrentLoadQmlDir();
+
+@@ -6013,6 +6015,51 @@
+ QVERIFY(result2.toBool());
+ }
+
++// verify that the property validator does not get confused when
++// multiple engines end up registering the same type, leading to
++// multiple entries in compositeTypes
++void tst_qqmllanguage::propertyValidatorMultiEngine()
++{
++ QQmlEngine engine1;
++ QQmlComponent c1(&engine1, testFileUrl("propertyValidatorMultiEngine/Consumer1.qml"));
++ QVERIFY2(c1.isReady(), qPrintable(c1.errorString()));
++
++ QQmlEngine engine2;
++ QQmlComponent c2(&engine2, testFileUrl("propertyValidatorMultiEngine/Consumer1.qml"));
++ QVERIFY2(c2.isReady(), qPrintable(c2.errorString()));
++
++ QQmlComponent c3(&engine1, testFileUrl("propertyValidatorMultiEngine/Consumer2.qml"));
++ QVERIFY2(c3.isReady(), qPrintable(c3.errorString()));
++}
++
++// Verify that qmlobject_can_qml_cast() still recognizes a composite type when
++// multiple engines have loaded the same QML file
++void tst_qqmllanguage::canQmlCastMultiEngine()
++{
++ const QUrl url = testFileUrl("canQmlCastMultiEngine/Main.qml");
++
++ QQmlEngine engine1;
++ QQmlComponent c1(&engine1, url);
++ QVERIFY2(c1.isReady(), qPrintable(c1.errorString()));
++ QScopedPointer<QObject> obj1(c1.create());
++ QVERIFY(obj1);
++
++ // A second engine loads the same file and registers another compilation unit
++ // (and thus another property cache) for Foo.
++ QQmlEngine engine2;
++ QQmlComponent c2(&engine2, url);
++ QVERIFY2(c2.isReady(), qPrintable(c2.errorString()));
++ QScopedPointer<QObject> obj2(c2.create());
++ QVERIFY(obj2);
++
++ // Call the typed function on engine1's object with engine1's Foo instance.
++ QQmlExpression expr(engine1.contextForObject(obj1.data()), obj1.data(),
++ QStringLiteral("check(theFoo)"));
++ const QVariant result = expr.evaluate();
++ QVERIFY2(!expr.hasError(), qPrintable(expr.error().description()));
++ QVERIFY(result.toBool());
++}
++
+ void tst_qqmllanguage::concurrentLoadQmlDir()
+ {
+ ThreadedTestHTTPServer server(dataDirectory());
^ permalink raw reply related [flat|nested] 2+ messages in thread
* [rpms/qt6-qtdeclarative] rawhide: Upstream backport:
@ 2026-07-14 5:41 Jan Grulich
0 siblings, 0 replies; 2+ messages in thread
From: Jan Grulich @ 2026-07-14 5:41 UTC (permalink / raw)
To: git-commits
A new commit has been pushed.
Repo : rpms/qt6-qtdeclarative
Branch : rawhide
Commit : 2bc3f001ec2964ce90237afc3102b075cc548a49
Author : Jan Grulich <jgrulich@redhat.com>
Date : 2026-07-14T07:41:14+02:00
Stats : +39/-1 in 2 file(s)
URL : https://src.fedoraproject.org/rpms/qt6-qtdeclarative/c/2bc3f001ec2964ce90237afc3102b075cc548a49?branch=rawhide
Log:
Upstream backport:
a11y: Guard against nullptr for scrollbar valueInterface
---
diff --git a/qt6-qtdeclarative.spec b/qt6-qtdeclarative.spec
index a7493be..99ab65e 100644
--- a/qt6-qtdeclarative.spec
+++ b/qt6-qtdeclarative.spec
@@ -16,7 +16,7 @@
Summary: Qt6 - QtDeclarative component
Name: qt6-%{qt_module}
Version: 6.11.1
-Release: 2%{?dist}
+Release: 3%{?dist}
License: LGPL-3.0-only OR GPL-3.0-only WITH Qt-GPL-exception-1.0
Url: http://www.qt.io
@@ -36,6 +36,7 @@ Source5: qv4global_p-multilib.h
## upstream patches
Patch0: qtdeclarative-dialogs-use-generic-qtquickcontrols-import-in-base-fallback-dialogs.patch
Patch1: qtdeclarative-qmltableinstancemodel-refactor-qmodelindex-calculation-out-of-qquicktableview.patch
+Patch2: qtdeclarative-a11y-guard-against-nullptr-for-scrollbar-valueinterface.patch
## upstreamable patches
@@ -754,6 +755,10 @@ make check -k -C tests ||:
%endif
%changelog
+* Tue Jul 14 2026 Jan Grulich <jgrulich@redhat.com> - 6.11.1-3
+- Upstream backport:
+ - a11y: Guard against nullptr for scrollbar valueInterface
+
* Mon May 25 2026 Jan Grulich <jgrulich@redhat.com> - 6.11.1-2
- Upstream backport:
- QQmlTableInstanceModel: refactor QModelIndex calculation out
diff --git a/qtdeclarative-a11y-guard-against-nullptr-for-scrollbar-valueinterface.patch b/qtdeclarative-a11y-guard-against-nullptr-for-scrollbar-valueinterface.patch
new file mode 100644
index 0000000..aac99c8
--- /dev/null
+++ b/qtdeclarative-a11y-guard-against-nullptr-for-scrollbar-valueinterface.patch
@@ -0,0 +1,33 @@
+From 0093e85bbff86a25f3ab069de8ac19b3d723f706 Mon Sep 17 00:00:00 2001
+From: Magnus Groß <magnus@mggross.com>
+Date: Sat, 30 May 2026 21:26:03 +0200
+Subject: [PATCH] a11y: Guard against nullptr for scrollbar valueInterface
+
+The regression was introduced in 3e233634d83, which mistakenly assumed
+that valueInterface cannot be nullptr.
+
+Fixes: QTBUG-146959
+Pick-to: 6.11
+Change-Id: Ia47a05c9da6bf3889b12475f737aeab20485fe59
+Reviewed-by: MohammadHossein Qanbari <mohammad.qanbari@qt.io>
+---
+
+diff --git a/src/quicktemplates/qquickscrollbar.cpp b/src/quicktemplates/qquickscrollbar.cpp
+index f7d0600..70c3b69 100644
+--- a/src/quicktemplates/qquickscrollbar.cpp
++++ b/src/quicktemplates/qquickscrollbar.cpp
+@@ -474,10 +474,10 @@
+ #if QT_CONFIG(accessibility)
+ if (QAccessible::isActive()) {
+ if (QAccessibleInterface *accessible = QAccessible::queryAccessibleInterface(q)) {
+- QAccessibleValueInterface *valueInterface = accessible->valueInterface();
+- Q_ASSERT(valueInterface);
+- QAccessibleValueChangeEvent event(q, valueInterface->currentValue());
+- QAccessible::updateAccessibility(&event);
++ if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) {
++ QAccessibleValueChangeEvent event(q, valueInterface->currentValue());
++ QAccessible::updateAccessibility(&event);
++ }
+ }
+ }
+ #endif
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-09-11 10:34 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-11 10:34 [rpms/qt6-qtdeclarative] rawhide: Upstream backport: Jan Grulich
-- strict thread matches above, loose matches on Subject: below --
2026-07-14 5:41 Jan Grulich
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox