From c86885735656a421b89ef547f6a6133aec4a7df2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Thu, 2 Dec 2021 09:26:18 +0200 Subject: Bound animatorjob value to the given range The value() might get called before updateCurrentTime has been called for the animator so the m_value has not been initialized. Bound the value to the given range in the function to ensure it doesn't return invalid values. Fixes: QTBUG-75799 Change-Id: I8d60430ed95082b975f49cf7c778e196f2fd5384 Reviewed-by: Volker Hilsheimer (cherry picked from commit e0850c918cbe32dc1aca7398becdd9b1bce4ce27) Reviewed-by: Qt Cherry-pick Bot --- src/quick/util/qquickanimatorjob.cpp | 11 +++++++++++ src/quick/util/qquickanimatorjob_p.h | 11 +++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp index 22c13752a3..b91d565601 100644 --- a/src/quick/util/qquickanimatorjob.cpp +++ b/src/quick/util/qquickanimatorjob.cpp @@ -285,6 +285,17 @@ qreal QQuickAnimatorJob::progress(int time) const return m_easing.valueForProgress((m_duration == 0) ? qreal(1) : qreal(time) / qreal(m_duration)); } +void QQuickAnimatorJob::boundValue() +{ + qreal rangeMin = m_from; + qreal rangeMax = m_to; + if (m_from > m_to) { + rangeMax = m_from; + rangeMin = m_to; + } + m_value = qBound(rangeMin, m_value, rangeMax); +} + qreal QQuickAnimatorJob::value() const { qreal value = m_to; diff --git a/src/quick/util/qquickanimatorjob_p.h b/src/quick/util/qquickanimatorjob_p.h index afc8d23a6c..10f94b0196 100644 --- a/src/quick/util/qquickanimatorjob_p.h +++ b/src/quick/util/qquickanimatorjob_p.h @@ -122,10 +122,16 @@ public: virtual void setTarget(QQuickItem *target); QQuickItem *target() const { return m_target; } - void setFrom(qreal from) { m_from = from; } + void setFrom(qreal from) { + m_from = from; + boundValue(); + } qreal from() const { return m_from; } - void setTo(qreal to) { m_to = to; } + void setTo(qreal to) { + m_to = to; + boundValue(); + } qreal to() const { return m_to; } void setDuration(int duration) { m_duration = duration; } @@ -171,6 +177,7 @@ protected: void debugAnimation(QDebug d) const override; qreal progress(int time) const; + void boundValue(); QPointer m_target; QQuickAnimatorController *m_controller; -- cgit v1.2.3 From 001c3ed8080b6b34d85936d3de145ba38cdf5e08 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 14 Dec 2021 16:16:20 +0100 Subject: Do not copy lookups It leads to data corruption. Also, be more careful about releasing the property cache. We can only do that if the qobjectlookup member of the union is active. Unfortunately we have to do a number of checks now, to make sure it is. In order to still keep the checks inline, we move some functions around. Fixes: QTBUG-99211 Change-Id: If6dd879e67b172e1a9035e83fbfacbe73c6c7476 Reviewed-by: Fabian Kosmale (cherry picked from commit e24effdceb3a504182ae271200408750991aa94a) Reviewed-by: Qt Cherry-pick Bot --- src/qml/jsruntime/qv4executablecompilationunit.cpp | 20 +--- src/qml/jsruntime/qv4lookup.cpp | 113 +++++++++++++++------ src/qml/jsruntime/qv4lookup_p.h | 25 ++++- src/qml/jsruntime/qv4qobjectwrapper.cpp | 14 +-- src/qml/jsruntime/qv4qobjectwrapper_p.h | 2 +- 5 files changed, 107 insertions(+), 67 deletions(-) diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp index 55ed888e7b..f5f76d2a9e 100644 --- a/src/qml/jsruntime/qv4executablecompilationunit.cpp +++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp @@ -296,24 +296,8 @@ void ExecutableCompilationUnit::unlink() propertyCaches.clear(); if (runtimeLookups) { - for (uint i = 0; i < data->lookupTableSize; ++i) { - QV4::Lookup &l = runtimeLookups[i]; - if (l.getter == QV4::QObjectWrapper::lookupGetter - || l.getter == QQmlTypeWrapper::lookupSingletonProperty) { - if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache) - pc->release(); - } else if (l.getter == QQmlValueTypeWrapper::lookupGetter - || l.getter == QQmlTypeWrapper::lookupSingletonProperty) { - if (QQmlPropertyCache *pc = l.qgadgetLookup.propertyCache) - pc->release(); - } - - if (l.qmlContextPropertyGetter == QQmlContextWrapper::lookupScopeObjectProperty - || l.qmlContextPropertyGetter == QQmlContextWrapper::lookupContextObjectProperty) { - if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache) - pc->release(); - } - } + for (uint i = 0; i < data->lookupTableSize; ++i) + runtimeLookups[i].releasePropertyCache(); } dependentScripts.clear(); diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index a91fe8f371..604a6002c8 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -41,6 +41,7 @@ #include "qv4jscall_p.h" #include "qv4string_p.h" #include +#include QT_BEGIN_NAMESPACE @@ -144,47 +145,76 @@ ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Va return l->resolvePrimitiveGetter(engine, object); } +static inline void setupObjectLookupTwoClasses(Lookup *l, const Lookup &first, const Lookup &second) +{ + Heap::InternalClass *ic1 = first.objectLookup.ic; + const uint offset1 = first.objectLookup.offset; + Heap::InternalClass *ic2 = second.objectLookup.ic; + const uint offset2 = second.objectLookup.offset; + + l->objectLookupTwoClasses.ic = ic1; + l->objectLookupTwoClasses.ic2 = ic2; + l->objectLookupTwoClasses.offset = offset1; + l->objectLookupTwoClasses.offset2 = offset2; +} + +static inline void setupProtoLookupTwoClasses(Lookup *l, const Lookup &first, const Lookup &second) +{ + const quintptr protoId1 = first.protoLookup.protoId; + const Value *data1 = first.protoLookup.data; + const quintptr protoId2 = second.protoLookup.protoId; + const Value *data2 = second.protoLookup.data; + + l->protoLookupTwoClasses.protoId = protoId1; + l->protoLookupTwoClasses.protoId2 = protoId2; + l->protoLookupTwoClasses.data = data1; + l->protoLookupTwoClasses.data2 = data2; +} + ReturnedValue Lookup::getterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object) { if (const Object *o = object.as()) { - Lookup first = *l; - Lookup second = *l; - ReturnedValue result = second.resolveGetter(engine, o); - - if (first.getter == getter0Inline && (second.getter == getter0Inline || second.getter == getter0MemberData)) { - l->objectLookupTwoClasses.ic = first.objectLookup.ic; - l->objectLookupTwoClasses.ic2 = second.objectLookup.ic; - l->objectLookupTwoClasses.offset = first.objectLookup.offset; - l->objectLookupTwoClasses.offset2 = second.objectLookup.offset; - l->getter = second.getter == getter0Inline ? getter0Inlinegetter0Inline : getter0Inlinegetter0MemberData; + // Do the resolution on a second lookup, then merge. + Lookup second; + memset(&second, 0, sizeof(Lookup)); + second.nameIndex = l->nameIndex; + second.getter = getterGeneric; + const ReturnedValue result = second.resolveGetter(engine, o); + + if (l->getter == getter0Inline + && (second.getter == getter0Inline || second.getter == getter0MemberData)) { + setupObjectLookupTwoClasses(l, *l, second); + l->getter = (second.getter == getter0Inline) + ? getter0Inlinegetter0Inline + : getter0Inlinegetter0MemberData; return result; } - if (first.getter == getter0MemberData && (second.getter == getter0Inline || second.getter == getter0MemberData)) { - l->objectLookupTwoClasses.ic = second.objectLookup.ic; - l->objectLookupTwoClasses.ic2 = first.objectLookup.ic; - l->objectLookupTwoClasses.offset = second.objectLookup.offset; - l->objectLookupTwoClasses.offset2 = first.objectLookup.offset; - l->getter = second.getter == getter0Inline ? getter0Inlinegetter0MemberData : getter0MemberDatagetter0MemberData; + + if (l->getter == getter0MemberData + && (second.getter == getter0Inline || second.getter == getter0MemberData)) { + setupObjectLookupTwoClasses(l, second, *l); + l->getter = (second.getter == getter0Inline) + ? getter0Inlinegetter0MemberData + : getter0MemberDatagetter0MemberData; return result; } - if (first.getter == getterProto && second.getter == getterProto) { - l->protoLookupTwoClasses.protoId = first.protoLookup.protoId; - l->protoLookupTwoClasses.protoId2 = second.protoLookup.protoId; - l->protoLookupTwoClasses.data = first.protoLookup.data; - l->protoLookupTwoClasses.data2 = second.protoLookup.data; + + + if (l->getter == getterProto && second.getter == getterProto) { + setupProtoLookupTwoClasses(l, *l, second); l->getter = getterProtoTwoClasses; return result; } - if (first.getter == getterProtoAccessor && second.getter == getterProtoAccessor) { - l->protoLookupTwoClasses.protoId = first.protoLookup.protoId; - l->protoLookupTwoClasses.protoId2 = second.protoLookup.protoId; - l->protoLookupTwoClasses.data = first.protoLookup.data; - l->protoLookupTwoClasses.data2 = second.protoLookup.data; + + if (l->getter == getterProtoAccessor && second.getter == getterProtoAccessor) { + setupProtoLookupTwoClasses(l, *l, second); l->getter = getterProtoAccessorTwoClasses; return result; } + // If any of the above options were true, the propertyCache was inactive. + second.releasePropertyCache(); } l->getter = getterFallback; @@ -371,7 +401,19 @@ ReturnedValue Lookup::getterIndexed(Lookup *l, ExecutionEngine *engine, const Va } l->getter = getterFallback; return getterFallback(l, engine, object); +} +ReturnedValue Lookup::getterQObject(Lookup *lookup, ExecutionEngine *engine, const Value &object) +{ + const auto revertLookup = [lookup, engine, &object]() { + lookup->qobjectLookup.propertyCache->release(); + lookup->qobjectLookup.propertyCache = nullptr; + lookup->getter = Lookup::getterGeneric; + return Lookup::getterGeneric(lookup, engine, object); + }; + + return QObjectWrapper::lookupGetterImpl( + lookup, engine, object, /*useOriginalProperty*/ false, revertLookup); } ReturnedValue Lookup::primitiveGetterProto(Lookup *l, ExecutionEngine *engine, const Value &object) @@ -463,23 +505,30 @@ bool Lookup::setterGeneric(Lookup *l, ExecutionEngine *engine, Value &object, co bool Lookup::setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { - Lookup first = *l; - Lookup second = *l; + // A precondition of this method is that l->objectLookup is the active variant of the union. + Q_ASSERT(l->setter == setter0MemberData || l->setter == setter0Inline); if (object.isObject()) { + + // As l->objectLookup is active, we can stash some members here, before resolving. + Heap::InternalClass *ic = l->objectLookup.ic; + const uint index = l->objectLookup.index; + if (!l->resolveSetter(engine, static_cast(&object), value)) { l->setter = setterFallback; return false; } if (l->setter == Lookup::setter0MemberData || l->setter == Lookup::setter0Inline) { - l->objectLookupTwoClasses.ic = first.objectLookup.ic; - l->objectLookupTwoClasses.ic2 = second.objectLookup.ic; - l->objectLookupTwoClasses.offset = first.objectLookup.index; - l->objectLookupTwoClasses.offset2 = second.objectLookup.index; + l->objectLookupTwoClasses.ic = ic; + l->objectLookupTwoClasses.ic2 = ic; + l->objectLookupTwoClasses.offset = index; + l->objectLookupTwoClasses.offset2 = index; l->setter = setter0setter0; return true; } + + l->releasePropertyCache(); } l->setter = setterFallback; diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index deb23d8c58..ce46186827 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -56,11 +56,17 @@ #include "qv4context_p.h" #include "qv4object_p.h" #include "qv4internalclass_p.h" +#include "qv4qmlcontext_p.h" +#include +#include QT_BEGIN_NAMESPACE namespace QV4 { +// Note: We cannot hide the copy ctor and assignment operator of this class because it needs to +// be trivially copyable. But you should never ever copy it. There are refcounted members +// in there. struct Q_QML_PRIVATE_EXPORT Lookup { union { ReturnedValue (*getter)(Lookup *l, ExecutionEngine *engine, const Value &object); @@ -187,6 +193,7 @@ struct Q_QML_PRIVATE_EXPORT Lookup { static ReturnedValue getterProtoAccessor(Lookup *l, ExecutionEngine *engine, const Value &object); static ReturnedValue getterProtoAccessorTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object); static ReturnedValue getterIndexed(Lookup *l, ExecutionEngine *engine, const Value &object); + static ReturnedValue getterQObject(Lookup *l, ExecutionEngine *engine, const Value &object); static ReturnedValue primitiveGetterProto(Lookup *l, ExecutionEngine *engine, const Value &object); static ReturnedValue primitiveGetterAccessor(Lookup *l, ExecutionEngine *engine, const Value &object); @@ -216,6 +223,20 @@ struct Q_QML_PRIVATE_EXPORT Lookup { void clear() { memset(&markDef, 0, sizeof(markDef)); } + + void releasePropertyCache() + { + if (getter == getterQObject + || getter == QQmlTypeWrapper::lookupSingletonProperty + || qmlContextPropertyGetter == QQmlContextWrapper::lookupScopeObjectProperty + || qmlContextPropertyGetter == QQmlContextWrapper::lookupContextObjectProperty) { + if (QQmlPropertyCache *pc = qobjectLookup.propertyCache) + pc->release(); + } else if (getter == QQmlValueTypeWrapper::lookupGetter) { + if (QQmlPropertyCache *pc = qgadgetLookup.propertyCache) + pc->release(); + } + } }; Q_STATIC_ASSERT(std::is_standard_layout::value); @@ -226,9 +247,7 @@ Q_STATIC_ASSERT(offsetof(Lookup, getter) == 0); inline void setupQObjectLookup( Lookup *lookup, const QQmlData *ddata, QQmlPropertyData *propertyData) { - if (QQmlPropertyCache *cache = lookup->qobjectLookup.propertyCache) - cache->release(); - + lookup->releasePropertyCache(); Q_ASSERT(ddata->propertyCache != nullptr); lookup->qobjectLookup.propertyCache = ddata->propertyCache; lookup->qobjectLookup.propertyCache->addref(); diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 91d7712be0..29780590b4 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -876,22 +876,10 @@ ReturnedValue QObjectWrapper::virtualResolveLookupGetter(const Object *object, E } QV4::setupQObjectLookup(lookup, ddata, property, This); - lookup->getter = QV4::QObjectWrapper::lookupGetter; + lookup->getter = QV4::Lookup::getterQObject; return lookup->getter(lookup, engine, *object); } -ReturnedValue QObjectWrapper::lookupGetter(Lookup *lookup, ExecutionEngine *engine, const Value &object) -{ - const auto revertLookup = [lookup, engine, &object]() { - lookup->qobjectLookup.propertyCache->release(); - lookup->qobjectLookup.propertyCache = nullptr; - lookup->getter = Lookup::getterGeneric; - return Lookup::getterGeneric(lookup, engine, object); - }; - - return lookupGetterImpl(lookup, engine, object, /*useOriginalProperty*/ false, revertLookup); -} - bool QObjectWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value) { diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index ae1b5b679b..51197243ad 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -183,7 +183,7 @@ struct Q_QML_EXPORT QObjectWrapper : public Object static ReturnedValue getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property); static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup); - static ReturnedValue lookupGetter(Lookup *l, ExecutionEngine *engine, const Value &object); + template static ReturnedValue lookupGetterImpl(Lookup *l, ExecutionEngine *engine, const Value &object, bool useOriginalProperty, ReversalFunctor revert); static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value); -- cgit v1.2.3 From 45c34bdda601bb44b15517b6a18a1fbfa0537e30 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 30 Nov 2021 15:30:55 +0100 Subject: QQuickItemViewTransitionAttached: Avoid dangling pointers The items referred to here can be deleted when the animation finishes. Use QPointer to zero them in that case. The test had to be removed because it uses QtQuickControls2, which is still in its own repository in 5.15. Fixes: QTBUG-84196 Change-Id: I695c9e91bd29d0583e4871d03ee946c40aa8a595 Reviewed-by: Fabian Kosmale Reviewed-by: Mitch Curtis Reviewed-by: Andrei Golubev (cherry picked from commit 0118a2d6b6347a444fef2b80a170caa606b669d2) Reviewed-by: Qt CI Bot --- src/quick/items/qquickitemviewtransition.cpp | 8 +++++++- src/quick/items/qquickitemviewtransition_p.h | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/quick/items/qquickitemviewtransition.cpp b/src/quick/items/qquickitemviewtransition.cpp index 462b9ae7ee..aaf3e7568a 100644 --- a/src/quick/items/qquickitemviewtransition.cpp +++ b/src/quick/items/qquickitemviewtransition.cpp @@ -555,9 +555,15 @@ void QQuickItemViewTransitionableItem::stopTransition() QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent) - : QObject(parent), m_item(nullptr), m_index(-1) + : QObject(parent), m_index(-1) { } + +QQuickItem *QQuickViewTransitionAttached::item() const +{ + return m_item.data(); +} + /*! \qmltype ViewTransition \instantiates QQuickViewTransitionAttached diff --git a/src/quick/items/qquickitemviewtransition_p.h b/src/quick/items/qquickitemviewtransition_p.h index d9ac8a8fc8..f969cbd9d7 100644 --- a/src/quick/items/qquickitemviewtransition_p.h +++ b/src/quick/items/qquickitemviewtransition_p.h @@ -202,7 +202,7 @@ public: QQuickViewTransitionAttached(QObject *parent); int index() const { return m_index; } - QQuickItem *item() const { return m_item; } + QQuickItem *item() const; QPointF destination() const { return m_destination; } QList targetIndexes() const { return m_targetIndexes; } @@ -224,7 +224,7 @@ private: QList m_targetIndexes; QList m_targetItems; - QQuickItem *m_item; + QPointer m_item; int m_index; }; -- cgit v1.2.3 From 85a74c3195cca9c5003cdfd325f3fe4a8579f3d7 Mon Sep 17 00:00:00 2001 From: Tarja Sundqvist Date: Fri, 31 Dec 2021 15:31:30 +0200 Subject: Bump version --- .qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qmake.conf b/.qmake.conf index aa2fe801ea..a9549f1eb1 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.8 +MODULE_VERSION = 5.15.9 -- cgit v1.2.3 From b2a4a61e8cb0839ba293783ac03c72f35c7b1307 Mon Sep 17 00:00:00 2001 From: Tony Leinonen Date: Tue, 4 May 2021 17:12:49 +0300 Subject: GridView: Set content position when changing cell size Content size was calculated before the new data was applied. This caused problems when calculating the column count while resizing the window. Fixes: QTBUG-92998 Change-Id: Ia4401c0e34cd11dc9e6c24a0320dbf0ca2f59ab9 Reviewed-by: Shawn Rutledge (cherry picked from commit 6254b383309a0c3cd273264466105a7e3599a1ed) Reviewed-by: Tony Leinonen --- src/quick/items/qquickgridview.cpp | 2 + .../auto/quick/qquickgridview/data/qtbug92998.qml | 52 ++++++++++++++++++++++ .../quick/qquickgridview/tst_qquickgridview.cpp | 19 ++++++++ 3 files changed, 73 insertions(+) create mode 100644 tests/auto/quick/qquickgridview/data/qtbug92998.qml diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp index f87b44a2d5..99cfec73dd 100644 --- a/src/quick/items/qquickgridview.cpp +++ b/src/quick/items/qquickgridview.cpp @@ -1653,6 +1653,7 @@ void QQuickGridView::setCellWidth(qreal cellWidth) d->updateViewport(); emit cellWidthChanged(); d->forceLayoutPolish(); + QQuickFlickable::setContentX(d->contentXForPosition(d->position())); } } @@ -1670,6 +1671,7 @@ void QQuickGridView::setCellHeight(qreal cellHeight) d->updateViewport(); emit cellHeightChanged(); d->forceLayoutPolish(); + QQuickFlickable::setContentY(d->contentYForPosition(d->position())); } } /*! diff --git a/tests/auto/quick/qquickgridview/data/qtbug92998.qml b/tests/auto/quick/qquickgridview/data/qtbug92998.qml new file mode 100644 index 0000000000..204e6d0b87 --- /dev/null +++ b/tests/auto/quick/qquickgridview/data/qtbug92998.qml @@ -0,0 +1,52 @@ +import QtQuick 2.0 + +Item { + width: 450 + height: 650 + GridView { + objectName: "gridview" + id: gridView + width: 450 + height: 650 + layoutDirection: Qt.RightToLeft + property int cells: calcCells(width) + cellWidth: width / cells + cellHeight: cellWidth + + delegate: Component { + Item { + width: gridView.cellWidth + height: gridView.cellHeight + Rectangle { + anchors { + fill: parent + margins: 10 + } + color: "green" + } + } + } + model: [ + { number: "1" }, + { number: "2" }, + { number: "3" }, + { number: "4" }, + { number: "5" }, + { number: "6" }, + { number: "7" }, + { number: "8" }, + { number: "9" }, + { number: "10" }, + { number: "11" }, + { number: "12" }, + { number: "13" }, + { number: "14" }, + { number: "15" }, + { number: "16" }]; + function calcCells(w) { + var rw = 120; + var c = Math.max(1, Math.round(w / rw)); + return c; + } + } +} diff --git a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp index 46e3457d6e..94ec4f44d5 100644 --- a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp +++ b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp @@ -215,6 +215,7 @@ private slots: void QTBUG_48870_fastModelUpdates(); void keyNavigationEnabled(); + void resizeDynamicCellWidthRtL(); void releaseItems(); private: @@ -6795,6 +6796,24 @@ void tst_QQuickGridView::QTBUG_48870_fastModelUpdates() } } +void tst_QQuickGridView::resizeDynamicCellWidthRtL() +{ + QScopedPointer window(createView()); + window->setSource(testFileUrl("qtbug92998.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + QQuickGridView *gridview = findItem(window->rootObject(), "gridview"); + QTRY_VERIFY(gridview != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); + gridview->setWidth(460); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); + QTRY_COMPARE(gridview->contentX(), 0.f); + gridview->setWidth(360); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); + QTRY_COMPARE(gridview->contentX(), 0.f); +} + void tst_QQuickGridView::releaseItems() { QScopedPointer view(createView()); -- cgit v1.2.3 From 82eacced37a2884e4960739051b6c36dc9c9f8da Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 3 Jan 2022 09:01:15 +0100 Subject: Treat unknown tablet device as stylus and create QTabletEvent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QQuickWindowPrivate::pointerEventInstance() needs to know the device type, to create the right kind of event. QTabletEvent::NoDevice exists, and platform plugins may use it, unfortunately. Now QQuickPointerDevice::tabletDevice() will assume that any device claiming to be a Pen is also a Stylus. Fixes: QTBUG-97771 Change-Id: I6c3f369025be5848e092a50f420b05fbd4e17cbd Reviewed-by: Tor Arne Vestbø --- src/quick/items/qquickevents.cpp | 2 ++ src/quick/items/qquickwindow.cpp | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp index 3ac8e19e9c..d433b194a5 100644 --- a/src/quick/items/qquickevents.cpp +++ b/src/quick/items/qquickevents.cpp @@ -712,6 +712,8 @@ QQuickPointerDevice *QQuickPointerDevice::tabletDevice(const QTabletEvent *event switch (event->pointerType()) { case QTabletEvent::Pen: ptype = Pen; + if (type == QQuickPointerDevice::UnknownDevice) + type = QQuickPointerDevice::Stylus; break; case QTabletEvent::Eraser: ptype = Eraser; diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 47bb63e26e..fd9392c502 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -2612,7 +2612,9 @@ QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QEvent *event) con } Q_ASSERT(dev); - return pointerEventInstance(dev, event->type())->reset(event); + auto pev = pointerEventInstance(dev, event->type()); + Q_ASSERT(pev); + return pev->reset(event); } void QQuickWindowPrivate::deliverPointerEvent(QQuickPointerEvent *event) -- cgit v1.2.3 From 0993a04445facd65ca1166d51c097e55a4fdd5e6 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Tue, 21 Dec 2021 09:20:17 +0100 Subject: QQmlJs::FixedPoolArray: fix UB (precondition violation) in allocate() Says ubsan: qqmljsfixedpoolarray_p.h:90:19: runtime error: null pointer passed as argument 2, which is declared to never be null Fix, like in so many other places, by a size check. Change-Id: I9181d6ecb467c2dc726978ce7f93b35a6bf2f944 Reviewed-by: Lars Knoll (cherry picked from commit d74e931f3fc2587ac6d1e2930acbbe54ea5be2b5) Reviewed-by: Qt Cherry-pick Bot --- src/qml/common/qqmljsfixedpoolarray_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qml/common/qqmljsfixedpoolarray_p.h b/src/qml/common/qqmljsfixedpoolarray_p.h index 8d2caff778..ec397837a9 100644 --- a/src/qml/common/qqmljsfixedpoolarray_p.h +++ b/src/qml/common/qqmljsfixedpoolarray_p.h @@ -86,7 +86,7 @@ public: if (QTypeInfo::isComplex) { for (int i = 0; i < count; ++i) new (data + i) T(vector.at(i)); - } else { + } else if (count) { memcpy(data, static_cast(vector.constData()), count * sizeof(T)); } } -- cgit v1.2.3 From 06d7d0d42d5275ef728a54b850d6e6320e9579e4 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 7 Jan 2022 10:05:43 +0100 Subject: qml{plugindump|importscanner}: Don't mix std::cerr and std::wcerr Apparently that causes output to be suppressed. Fixes: QTBUG-99400 Change-Id: I4ac6a66a10c7d2c27dfc1efa6d52afa60bdc58d6 Reviewed-by: Friedemann Kleint Reviewed-by: Fawzi Mohamed Reviewed-by: Volker Hilsheimer (cherry picked from commit 5fa9093191c8a0fbf765f3b51a68dea996fed76e) --- tools/qmlimportscanner/main.cpp | 6 +++--- tools/qmlplugindump/main.cpp | 12 +----------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/tools/qmlimportscanner/main.cpp b/tools/qmlimportscanner/main.cpp index 7bf8dddf3d..9f6a89810f 100644 --- a/tools/qmlimportscanner/main.cpp +++ b/tools/qmlimportscanner/main.cpp @@ -74,18 +74,18 @@ inline QString directoryLiteral() { return QStringLiteral("directory"); } void printUsage(const QString &appNameIn) { - const std::wstring appName = appNameIn.toStdWString(); + const std::string appName = appNameIn.toStdString(); #ifndef QT_BOOTSTRAPPED const QString qmlPath = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath); #else const QString qmlPath = QStringLiteral("/home/user/dev/qt-install/qml"); #endif - std::wcerr + std::cerr << "Usage: " << appName << " -rootPath path/to/app/qml/directory -importPath path/to/qt/qml/directory\n" " " << appName << " -qmlFiles file1 file2 -importPath path/to/qt/qml/directory\n" " " << appName << " -qrcFiles file1.qrc file2.qrc -importPath path/to/qt/qml/directory\n\n" "Example: " << appName << " -rootPath . -importPath " - << QDir::toNativeSeparators(qmlPath).toStdWString() + << QDir::toNativeSeparators(qmlPath).toStdString() << '\n'; } diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp index 05c7f75044..8c9db36837 100644 --- a/tools/qmlplugindump/main.cpp +++ b/tools/qmlplugindump/main.cpp @@ -991,19 +991,9 @@ bool compactDependencies(QStringList *dependencies) return false; } -inline std::wostream &operator<<(std::wostream &str, const QString &s) -{ -#ifdef Q_OS_WIN - str << reinterpret_cast(s.utf16()); -#else - str << s.toStdWString(); -#endif - return str; -} - void printDebugMessage(QtMsgType, const QMessageLogContext &, const QString &msg) { - std::wcerr << msg << std::endl; + std::cerr << msg.toStdString() << std::endl; // In case of QtFatalMsg the calling code will abort() when appropriate. } -- cgit v1.2.3 From 18ec3279f92d248fd228fc2dc1e4a70ff5f730bd Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 4 Jan 2022 15:46:07 +0100 Subject: Assert that QQmlDelegateModel's count can't be less than zero I was running into a crash (it didn't reproduce with a minimal example, and I'm still not sure exactly what caused it) related to models and views, and saw that there m_count was negative, which shouldn't be possible. Adding this new assertion allowed me to find the issue in my code. Change-Id: Ie467e749dbf95799618bd04591e50b0038cf3399 Reviewed-by: Qt CI Bot Reviewed-by: Richard Moe Gustavsen (cherry picked from commit d70b4ab2e58bcfd5e65c1d11a79020bb3e2906c0) Reviewed-by: Qt Cherry-pick Bot --- src/qmlmodels/qqmldelegatemodel.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp index e256964029..751d9e301e 100644 --- a/src/qmlmodels/qqmldelegatemodel.cpp +++ b/src/qmlmodels/qqmldelegatemodel.cpp @@ -1728,6 +1728,7 @@ void QQmlDelegateModel::_q_itemsRemoved(int index, int count) return; d->m_count -= count; + Q_ASSERT(d->m_count >= 0); const QList cache = d->m_cache; //Prevents items being deleted in remove loop for (QQmlDelegateModelItem *item : cache) -- cgit v1.2.3 From acaa14e51a5b7e1ea6f43bf61c04839efaf2ab1a Mon Sep 17 00:00:00 2001 From: Maximilian Goldstein Date: Thu, 6 Feb 2020 12:00:08 +0100 Subject: Blacklist flakey tst_QPauseAnimationJob::multipleSequentialGroups on macOS Task-number: QTBUG-81938 Change-Id: I9ced28d246161c87b5751699857dd0598121176e Reviewed-by: Simon Hausmann (cherry picked from commit b9b860dc51eb11e2b6c8d95ce85f48057e542df6) Reviewed-by: Fabian Kosmale --- tests/auto/qml/animation/qpauseanimationjob/BLACKLIST | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 tests/auto/qml/animation/qpauseanimationjob/BLACKLIST diff --git a/tests/auto/qml/animation/qpauseanimationjob/BLACKLIST b/tests/auto/qml/animation/qpauseanimationjob/BLACKLIST new file mode 100644 index 0000000000..33799b6528 --- /dev/null +++ b/tests/auto/qml/animation/qpauseanimationjob/BLACKLIST @@ -0,0 +1,3 @@ +[multipleSequentialGroups] +macos ci + -- cgit v1.2.3 From f9f69fe0ac2baf98e1154ec37e104238f4670ed5 Mon Sep 17 00:00:00 2001 From: Ivan Tkachenko Date: Fri, 22 Oct 2021 17:13:15 +0300 Subject: QQmlLoggingCategory: Avoid unnecessary warnings from setters Assigning same value should be a no-op, especially because such assignments may happen without explicit user/developer intent. For example, it can be triggered with QQmlEngine::retranslate() call on 5.15 and early 6.x branches. Since the recent optimizations to retranslate() which now only forces to re-evaluate what's really dependent on qsTr, it became harder, but still possible to pull it off. Fixes: QTBUG-97717 Change-Id: I60ca8e36ed98a15ea5f3c15290865cec27084fbc Reviewed-by: Ulf Hermann (cherry picked from commit 7136df0f8ed2b691f5291712fdeaf401072b32fd) Reviewed-by: Fabian Kosmale --- src/qml/qml/qqmlloggingcategory.cpp | 17 ++++++++++---- tests/auto/qml/qqmlconsole/data/assert.qml | 13 ++++++----- .../qml/qqmlconsole/data/categorized_logging.qml | 9 +++++--- tests/auto/qml/qqmlconsole/data/exception.qml | 4 ++-- tests/auto/qml/qqmlconsole/data/logging.qml | 21 +++++++++-------- tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp | 27 ++++++++++++++-------- 6 files changed, 56 insertions(+), 35 deletions(-) diff --git a/src/qml/qml/qqmlloggingcategory.cpp b/src/qml/qml/qqmlloggingcategory.cpp index 2e3277795a..d7df2a1fbc 100644 --- a/src/qml/qml/qqmlloggingcategory.cpp +++ b/src/qml/qml/qqmlloggingcategory.cpp @@ -129,7 +129,7 @@ void QQmlLoggingCategory::componentComplete() { m_initialized = true; if (m_name.isNull()) { - qmlWarning(this) << QLatin1String("Declaring the name of the LoggingCategory is mandatory and cannot be changed later !"); + qmlWarning(this) << QLatin1String("Declaring the name of a LoggingCategory is mandatory and cannot be changed later"); } else { QScopedPointer category(new QLoggingCategory(m_name.constData(), QtMsgType(m_defaultLogLevel))); m_category.swap(category); @@ -138,23 +138,30 @@ void QQmlLoggingCategory::componentComplete() void QQmlLoggingCategory::setDefaultLogLevel(DefaultLogLevel defaultLogLevel) { + if (m_defaultLogLevel == defaultLogLevel) + return; + if (m_initialized) { - qmlWarning(this) << QLatin1String("The defaultLogLevel of a LoggingCategory cannot be changed after the Item is created"); + qmlWarning(this) << QLatin1String("The defaultLogLevel of a LoggingCategory cannot be changed after the component is completed"); return; } m_defaultLogLevel = defaultLogLevel; } - void QQmlLoggingCategory::setName(const QString &name) { + const QByteArray newName = name.toUtf8(); + + if (m_name == newName) + return; + if (m_initialized) { - qmlWarning(this) << QLatin1String("The name of a LoggingCategory cannot be changed after the Item is created"); + qmlWarning(this) << QLatin1String("The name of a LoggingCategory cannot be changed after the component is completed"); return; } - m_name = name.toUtf8(); + m_name = newName; } #include "moc_qqmlloggingcategory_p.cpp" diff --git a/tests/auto/qml/qqmlconsole/data/assert.qml b/tests/auto/qml/qqmlconsole/data/assert.qml index dd580e2a72..9687437c48 100644 --- a/tests/auto/qml/qqmlconsole/data/assert.qml +++ b/tests/auto/qml/qqmlconsole/data/assert.qml @@ -29,21 +29,22 @@ import QtQuick 2.0 QtObject { - property int q:1 + property int q: 1 + function assertFail() { - console.assert(0, "This will fail too") + console.assert(0, "This will fail too"); } Component.onCompleted: { - var x = 12; + const x = 12; console.assert(x == 12, "This will pass"); try { - console.assert(x < 12, "This will fail"); + console.assert(x < 12, "This will fail"); } catch (e) { console.log(e); } - console.assert("x < 12", "This will pass too") + console.assert("x < 12", "This will pass too"); assertFail(); - console.assert(1) + console.assert(1); } } diff --git a/tests/auto/qml/qqmlconsole/data/categorized_logging.qml b/tests/auto/qml/qqmlconsole/data/categorized_logging.qml index d593f0dfa1..6d471e7f80 100644 --- a/tests/auto/qml/qqmlconsole/data/categorized_logging.qml +++ b/tests/auto/qml/qqmlconsole/data/categorized_logging.qml @@ -40,7 +40,7 @@ import QtQuick 2.12 Item { - id:root + id: root LoggingCategory { id: testCategory @@ -69,8 +69,11 @@ Item { console.warn(testCategoryStartingFromWarning, "console.warn"); console.error(testCategoryStartingFromWarning, "console.error"); - testCategory.name = "qt.test2"; - testCategory.defaultLogLevel = LoggingCategory.Debug; + testCategory.name = "qt.test"; // should be silent + testCategoryStartingFromWarning.name = "qt.test.other"; // should issue a warning + + testCategory.defaultLogLevel = LoggingCategory.Debug; // should be silent + testCategoryStartingFromWarning.defaultLogLevel = LoggingCategory.Debug; // should issue a warning console.error(emptyCategory, "console.error"); } diff --git a/tests/auto/qml/qqmlconsole/data/exception.qml b/tests/auto/qml/qqmlconsole/data/exception.qml index 63afd18828..b9b83525e8 100644 --- a/tests/auto/qml/qqmlconsole/data/exception.qml +++ b/tests/auto/qml/qqmlconsole/data/exception.qml @@ -30,12 +30,12 @@ import QtQuick 2.0 QtObject { function exceptionFail() { - console.exception("Exception 2") + console.exception("Exception 2"); } Component.onCompleted: { try { - console.exception("Exception 1") + console.exception("Exception 1"); } catch (e) { console.log(e); } diff --git a/tests/auto/qml/qqmlconsole/data/logging.qml b/tests/auto/qml/qqmlconsole/data/logging.qml index f5eaeb442a..ac3884bc8e 100644 --- a/tests/auto/qml/qqmlconsole/data/logging.qml +++ b/tests/auto/qml/qqmlconsole/data/logging.qml @@ -30,7 +30,8 @@ import QtQuick 2.0 QtObject { - id:root + id: root + required property var customObject required property var stringListProperty @@ -49,14 +50,14 @@ QtObject { consoleCount(); consoleCount(); - var a = [1, 2]; - var b = {a: "hello", d: 1 }; - b.toString = function() { return JSON.stringify(b) } - var c - var d = 12; - var e = function() { return 5;}; - var f = true; - var g = {toString: function() { throw new Error('toString'); }}; + const a = [1, 2]; + const b = { a: "hello", d: 1 }; + b.toString = function() { return JSON.stringify(b); } + let c; + const d = 12; + const e = function() { return 5; }; + const f = true; + const g = { toString: function() { throw new Error('toString'); } }; console.log(a); console.log(b); @@ -79,6 +80,6 @@ QtObject { return; } - throw ("console.log(exception) should have raised an exception"); + throw "console.log(exception) should have raised an exception"; } } diff --git a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp index 48613d04f1..3a25dfb10d 100644 --- a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp +++ b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp @@ -134,18 +134,27 @@ void tst_qqmlconsole::categorized_logging() QVERIFY(messageHandler.messages().contains("qt.test.warning: console.error")); QString emptyCategory = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(56).arg(5) + - "QML LoggingCategory: Declaring the name of the LoggingCategory is mandatory and cannot be changed later !"; + "QML LoggingCategory: Declaring the name of a LoggingCategory is mandatory and cannot be changed later"; QVERIFY(messageHandler.messages().contains(emptyCategory)); - QString changedCategory = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(45).arg(5) + - "QML LoggingCategory: The name of a LoggingCategory cannot be changed after the Item is created"; + + QString notChangedCategory = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(45).arg(5) + + "QML LoggingCategory: The name of a LoggingCategory cannot be changed after the component is completed"; + QVERIFY(!messageHandler.messages().contains(notChangedCategory)); + QString changedCategory = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(50).arg(5) + + "QML LoggingCategory: The name of a LoggingCategory cannot be changed after the component is completed"; QVERIFY(messageHandler.messages().contains(changedCategory)); - QString changedDefaultLogLevel = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(45).arg(5) + - "QML LoggingCategory: The defaultLogLevel of a LoggingCategory cannot be changed after the Item is created"; + + QString notChangedDefaultLogLevel = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(45).arg(5) + + "QML LoggingCategory: The defaultLogLevel of a LoggingCategory cannot be changed after the component is completed"; + QVERIFY(!messageHandler.messages().contains(notChangedDefaultLogLevel)); + QString changedDefaultLogLevel = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(50).arg(5) + + "QML LoggingCategory: The defaultLogLevel of a LoggingCategory cannot be changed after the component is completed"; QVERIFY(messageHandler.messages().contains(changedDefaultLogLevel)); - QString useEmptyCategory = "default: " + QString::fromLatin1("%1:%2: ").arg(testUrl.toString()).arg(75) + + + QString useEmptyCategory = "default: " + QString::fromLatin1("%1:%2: ").arg(testUrl.toString()).arg(78) + "Error: A QmlLoggingCatgory was provided without a valid name"; QVERIFY(messageHandler.messages().contains(useEmptyCategory)); @@ -188,11 +197,11 @@ void tst_qqmlconsole::testAssert() // assert() QString assert1 = "This will fail\n" + - QString::fromLatin1("onCompleted (%1:%2)").arg(testUrl.toString()).arg(41); + QString::fromLatin1("onCompleted (%1:%2)").arg(testUrl.toString()).arg(42); QString assert2 = "This will fail too\n" + - QString::fromLatin1("assertFail (%1:%2)\n").arg(testUrl.toString()).arg(34) + - QString::fromLatin1("onCompleted (%1:%2)").arg(testUrl.toString()).arg(46); + QString::fromLatin1("assertFail (%1:%2)\n").arg(testUrl.toString()).arg(35) + + QString::fromLatin1("onCompleted (%1:%2)").arg(testUrl.toString()).arg(47); QTest::ignoreMessage(QtCriticalMsg, qPrintable(assert1)); QTest::ignoreMessage(QtCriticalMsg, qPrintable(assert2)); -- cgit v1.2.3 From 25d0cf2c41d48d6f5830f634aea2bb067fe36d02 Mon Sep 17 00:00:00 2001 From: Tarja Sundqvist Date: Thu, 20 Jan 2022 17:16:46 +0200 Subject: Blacklist containsDrag_internal on Ubuntu 20.04 Test passes on Ubuntu 18.04 and SLES machines. This test failure is preventing usege of significant flag for Ubuntu 20.04 in the tqtc/lts-5.15 branch. Task-number: QTBUG-99765 Change-Id: Iaa5df1db5d74bc8b7d602f3f5644f4eeeeda5d80 Reviewed-by: Volker Hilsheimer --- tests/auto/quick/qquickdroparea/BLACKLIST | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 tests/auto/quick/qquickdroparea/BLACKLIST diff --git a/tests/auto/quick/qquickdroparea/BLACKLIST b/tests/auto/quick/qquickdroparea/BLACKLIST new file mode 100644 index 0000000000..d5963a692b --- /dev/null +++ b/tests/auto/quick/qquickdroparea/BLACKLIST @@ -0,0 +1,4 @@ +# Blacklist for testing +# QTBUG-99765 +[containsDrag_internal] +ubuntu 20.04 -- cgit v1.2.3 From 13fb1bf415a941a74b91e375536e9ec1792f4392 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 20 Jan 2022 17:37:44 +0100 Subject: Adjust default max call depth for QNX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QNX by default has smaller stacks than other platforms. Change-Id: Ia83d4e12c0fd24c51069777db2283d456c49800f Reviewed-by: Andrei Golubev Reviewed-by: Fabian Kosmale Reviewed-by: Pasi Petäjäjärvi (cherry picked from commit 7680fc7beed9c9f8e3883ac1796ef332cf40a4c8) Reviewed-by: Qt Cherry-pick Bot --- src/qml/doc/src/javascript/finetuning.qdoc | 9 ++++++--- src/qml/jsruntime/qv4engine.cpp | 4 ++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/qml/doc/src/javascript/finetuning.qdoc b/src/qml/doc/src/javascript/finetuning.qdoc index fcd710db8b..35310ee051 100644 --- a/src/qml/doc/src/javascript/finetuning.qdoc +++ b/src/qml/doc/src/javascript/finetuning.qdoc @@ -82,9 +82,12 @@ Running JavaScript code can be influenced by a few environment variables, partic \li \c{QV4_MAX_CALL_DEPTH} \li Stack overflows when running (as opposed to compiling) JavaScript are prevented by controlling the call depth: the number of nested function invocations. By - default, an exception is generated if the call depth exceeds 1234. If it contains a - number, this environment variable overrides the maximum call depth. Beware that the - recursion limit when compiling JavaScript is not affected. + default, an exception is generated if the call depth exceeds a maximum number tuned + to the platform's default stack size. If the \c{QV4_MAX_CALL_DEPTH} environment + variable contains a number, this number is used as maximum call depth. Beware that + the recursion limit when compiling JavaScript is not affected. The default maximum + call depth is 1234 on most platforms. On QNX it is 640 because on QNX the default + stack size is smaller than on most platforms. \row \li \c{QV4_MM_AGGRESSIVE_GC} \li Setting this environment variable runs the garbage collector before each memory diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 8d0430f732..f66de35428 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -310,7 +310,11 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) maxCallDepth = qEnvironmentVariableIntValue("QV4_MAX_CALL_DEPTH", &ok); if (!ok || maxCallDepth <= 0) { #if defined(QT_NO_DEBUG) && !defined(__SANITIZE_ADDRESS__) && !__has_feature(address_sanitizer) +#ifdef Q_OS_QNX + maxCallDepth = 640; // QNX's stack is only 512k by default +#else maxCallDepth = 1234; +#endif #else // no (tail call) optimization is done, so there'll be a lot mare stack frames active maxCallDepth = 200; -- cgit v1.2.3 From 4cff7c7adc86a7716b3c01f4f859d96ad9429417 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 24 Jan 2022 09:04:11 +0100 Subject: Use tree hash rather than commit hash in .tag file We want equal source packages to have the same .tag file, even if their commit hashes differ. Fixes: QTBUG-99608 Change-Id: Ide5047acec78fdd91617577b3c2125feb0b2bdf4 Reviewed-by: Fabian Kosmale (cherry picked from commit 17dcba699566bfe052bf2c320e07c2c7cc53094b) --- .tag | 2 +- src/qml/common/common.pri | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.tag b/.tag index 6828f88dcb..8b42f85cf5 100644 --- a/.tag +++ b/.tag @@ -1 +1 @@ -$Format:%H$ +$Format:%T$ diff --git a/src/qml/common/common.pri b/src/qml/common/common.pri index b333c0f6d9..b824812d27 100644 --- a/src/qml/common/common.pri +++ b/src/qml/common/common.pri @@ -1,8 +1,8 @@ !build_pass { # Create a header containing a hash that describes this library. For a # released version of Qt, we'll use the .tag file that is updated by git - # archive with the commit hash. For unreleased versions, we'll ask git - # describe. Note that it won't update unless qmake is run again, even if + # archive with the tree hash. For unreleased versions, we'll ask git + # rev-parse. Note that it won't update unless qmake is run again, even if # the commit change also changed something in this library. tagFile = $$PWD/../../.tag tag = @@ -10,7 +10,7 @@ tag = $$cat($$tagFile, singleline) QMAKE_INTERNAL_INCLUDED_FILES += $$tagFile } - !equals(tag, "$${LITERAL_DOLLAR}Format:%H$${LITERAL_DOLLAR}") { + !equals(tag, "$${LITERAL_DOLLAR}Format:%T$${LITERAL_DOLLAR}") { QML_COMPILE_HASH = $$tag } else:exists($$PWD/../../.git) { commit = $$system(git rev-parse HEAD) -- cgit v1.2.3 From 00baf1f024fa1ce489898548dd4387042f67c554 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 24 Jan 2022 16:49:01 +0100 Subject: Don't blacklist tst_QQuickFramebufferObject::everything on b2qt Put back the [testInvalidate] condition accidentally removed while removing the first of the platforms it formerly guarded. Amends 6336763588b45a2eeae6af29f5e4ba705b64b4d6 Task-number: QTBUG-64470 Task-number: QTBUG-65614 Change-Id: I494c3359c027696dae795874e1f0337102738fe7 Reviewed-by: Marc Mutz (cherry picked from commit affde02775e24047ff6e61651a3095654d2e3bba) Reviewed-by: Qt Cherry-pick Bot --- tests/auto/quick/qquickframebufferobject/BLACKLIST | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/auto/quick/qquickframebufferobject/BLACKLIST b/tests/auto/quick/qquickframebufferobject/BLACKLIST index 93dd7e9d1c..cf30c293dd 100644 --- a/tests/auto/quick/qquickframebufferobject/BLACKLIST +++ b/tests/auto/quick/qquickframebufferobject/BLACKLIST @@ -1,3 +1,4 @@ +[testInvalidate) # QTBUG-65614 b2qt [testThatStuffWorks] -- cgit v1.2.3 From 1c2a34f37675911d2948bb7805d108ae764d0b8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Delf=20Neum=C3=A4rker?= Date: Thu, 9 Dec 2021 10:28:15 +0100 Subject: Fix edge cases in arcTo The implementation is mathematically sound, but due to floating point arithmetic the code would sometimes call acos with values very slightly out of the valid [-1..1] interval. Using hypot and atan2 instead gives the correct result. Fixes: QTBUG-49049 Change-Id: I0185514a63dc2c99cb67e1f9951aac0ac32b5fd8 Reviewed-by: Giuseppe D'Angelo (cherry picked from commit c1938ddbb45c75593c8a21aaec2420f8f2c7b3d8) Reviewed-by: Qt Cherry-pick Bot --- src/quick/items/context2d/qquickcontext2d.cpp | 29 +++++++++++---------------- src/quick/items/context2d/qquickcontext2d_p.h | 2 +- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp index 4ae8018f3f..7c309bef35 100644 --- a/src/quick/items/context2d/qquickcontext2d.cpp +++ b/src/quick/items/context2d/qquickcontext2d.cpp @@ -3892,16 +3892,16 @@ void QQuickContext2D::bezierCurveTo(qreal cp1x, qreal cp1y, m_path.cubicTo(QPointF(cp1x, cp1y), QPointF(cp2x, cp2y), pt); } -void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radius) +void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, qreal radius) { QPointF p0(m_path.currentPosition()); QPointF p1p0((p0.x() - p1.x()), (p0.y() - p1.y())); QPointF p1p2((p2.x() - p1.x()), (p2.y() - p1.y())); - float p1p0_length = std::sqrt(p1p0.x() * p1p0.x() + p1p0.y() * p1p0.y()); - float p1p2_length = std::sqrt(p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y()); + qreal p1p0_length = std::hypot(p1p0.x(), p1p0.y()); + qreal p1p2_length = std::hypot(p1p2.x(), p1p2.y()); - double cos_phi = (p1p0.x() * p1p2.x() + p1p0.y() * p1p2.y()) / (p1p0_length * p1p2_length); + qreal cos_phi = QPointF::dotProduct(p1p0, p1p2) / (p1p0_length * p1p2_length); // The points p0, p1, and p2 are on the same straight line (HTML5, 4.8.11.1.8) // We could have used areCollinear() here, but since we're reusing @@ -3911,16 +3911,16 @@ void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radiu return; } - float tangent = radius / std::tan(std::acos(cos_phi) / 2); - float factor_p1p0 = tangent / p1p0_length; + qreal tangent = radius / std::tan(std::acos(cos_phi) / 2); + qreal factor_p1p0 = tangent / p1p0_length; QPointF t_p1p0((p1.x() + factor_p1p0 * p1p0.x()), (p1.y() + factor_p1p0 * p1p0.y())); QPointF orth_p1p0(p1p0.y(), -p1p0.x()); - float orth_p1p0_length = std::sqrt(orth_p1p0.x() * orth_p1p0.x() + orth_p1p0.y() * orth_p1p0.y()); - float factor_ra = radius / orth_p1p0_length; + qreal orth_p1p0_length = std::hypot(orth_p1p0.x(), orth_p1p0.y()); + qreal factor_ra = radius / orth_p1p0_length; // angle between orth_p1p0 and p1p2 to get the right vector orthographic to p1p0 - double cos_alpha = (orth_p1p0.x() * p1p2.x() + orth_p1p0.y() * p1p2.y()) / (orth_p1p0_length * p1p2_length); + qreal cos_alpha = QPointF::dotProduct(orth_p1p0, p1p2) / (orth_p1p0_length * p1p2_length); if (cos_alpha < 0.f) orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y()); @@ -3928,20 +3928,15 @@ void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radiu // calculate angles for addArc orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y()); - float sa = std::acos(orth_p1p0.x() / orth_p1p0_length); - if (orth_p1p0.y() < 0.f) - sa = 2 * M_PI - sa; + qreal sa = std::atan2(orth_p1p0.y(), orth_p1p0.x()); // anticlockwise logic bool anticlockwise = false; - float factor_p1p2 = tangent / p1p2_length; + qreal factor_p1p2 = tangent / p1p2_length; QPointF t_p1p2((p1.x() + factor_p1p2 * p1p2.x()), (p1.y() + factor_p1p2 * p1p2.y())); QPointF orth_p1p2((t_p1p2.x() - p.x()), (t_p1p2.y() - p.y())); - float orth_p1p2_length = std::sqrt(orth_p1p2.x() * orth_p1p2.x() + orth_p1p2.y() * orth_p1p2.y()); - float ea = std::acos(orth_p1p2.x() / orth_p1p2_length); - if (orth_p1p2.y() < 0) - ea = 2 * M_PI - ea; + qreal ea = std::atan2(orth_p1p2.y(), orth_p1p2.x()); if ((sa > ea) && ((sa - ea) < M_PI)) anticlockwise = true; if ((sa < ea) && ((ea - sa) > M_PI)) diff --git a/src/quick/items/context2d/qquickcontext2d_p.h b/src/quick/items/context2d/qquickcontext2d_p.h index e1f2ec71ea..f2d3d737f7 100644 --- a/src/quick/items/context2d/qquickcontext2d_p.h +++ b/src/quick/items/context2d/qquickcontext2d_p.h @@ -241,7 +241,7 @@ public: void arc(qreal x, qreal y, qreal radius, qreal startAngle, qreal endAngle, bool anticlockwise); - void addArcTo(const QPointF& p1, const QPointF& p2, float radius); + void addArcTo(const QPointF& p1, const QPointF& p2, qreal radius); bool isPointInPath(qreal x, qreal y) const; -- cgit v1.2.3 From dd0fddd795b8301e5a8e809f5983d6eb5c1d45ea Mon Sep 17 00:00:00 2001 From: Tony Leinonen Date: Wed, 22 Dec 2021 18:25:57 +0200 Subject: Fix incorrect behavior after displace transition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit to.x and to.y use itemX and itemY. This caused them to be off sync. Override item's fromValues with itemX and itemY calls to sync them back. Task-number: QTBUG-89193 Change-Id: If65f11a55101ee7cbc463806bcef0072fea00ebd Reviewed-by: Qt CI Bot Reviewed-by: Tomi Korpipää Reviewed-by: Shawn Rutledge (cherry picked from commit ebcdde7128c542acddcb07f7abf164492485f4a1) Reviewed-by: Qt Cherry-pick Bot --- src/quick/items/qquickitemviewtransition.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/quick/items/qquickitemviewtransition.cpp b/src/quick/items/qquickitemviewtransition.cpp index aaf3e7568a..75615054c6 100644 --- a/src/quick/items/qquickitemviewtransition.cpp +++ b/src/quick/items/qquickitemviewtransition.cpp @@ -125,6 +125,8 @@ void QQuickItemViewTransitionJob::startTransition(QQuickItemViewTransitionableIt actions << QQuickStateAction(item->item, QLatin1String("x"), QVariant(to.x())); actions << QQuickStateAction(item->item, QLatin1String("y"), QVariant(to.y())); + actions[0].fromValue = item->itemX(); + actions[1].fromValue = item->itemY(); m_transitioner->runningJobs << this; QQuickTransitionManager::transition(actions, trans, item->item); } -- cgit v1.2.3 From 2cafa71c961494dee39388dbffb33299747709a8 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 15 Dec 2021 11:42:23 +0100 Subject: tst_qquickimageprovider: fix some memleaks QTest::toString() returns a heap-allocated char pointer that must be delete[]ed after use. Instead of abusing QTest::toString(), use QTest::addRow(), which features printf-style formatting for the label. Found by lsan, which was going completely wild. Change-Id: I53f2aa1dce7a128c964a2b02420c65a410bf9b15 Reviewed-by: Fabian Kosmale (cherry picked from commit e95a43fb7666d6cf6095598c8bb9bbc1de9c3eb3) Reviewed-by: Qt Cherry-pick Bot --- .../tst_qquickimageprovider.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp b/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp index 9dc9ad53ea..cb9e8d1ce2 100644 --- a/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp +++ b/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp @@ -72,7 +72,7 @@ private slots: private: QString newImageFileName() const; - void fillRequestTestsData(const QString &id); + void fillRequestTestsData(const char *id); void runTest(bool async, QQuickImageProvider *provider); }; @@ -161,7 +161,7 @@ QString tst_qquickimageprovider::newImageFileName() const return QString("image://test/image-%1.png").arg(count++); } -void tst_qquickimageprovider::fillRequestTestsData(const QString &id) +void tst_qquickimageprovider::fillRequestTestsData(const char *id) { QTest::addColumn("source"); QTest::addColumn("imageId"); @@ -170,39 +170,39 @@ void tst_qquickimageprovider::fillRequestTestsData(const QString &id) QTest::addColumn("error"); QString fileName = newImageFileName(); - QTest::newRow(QTest::toString(id + " simple test")) + QTest::addRow("%s simple test", id) << "image://test/" + fileName << fileName << "" << QSize(100,100) << ""; fileName = newImageFileName(); - QTest::newRow(QTest::toString(id + " simple test with capitalization"))//As it's a URL, should make no difference + QTest::addRow("%s simple test with capitalization", id)//As it's a URL, should make no difference << "image://Test/" + fileName << fileName << "" << QSize(100,100) << ""; fileName = newImageFileName(); - QTest::newRow(QTest::toString(id + " url with no id")) + QTest::addRow("%s url with no id", id) << "image://test/" + fileName << "" + fileName << "" << QSize(100,100) << ""; fileName = newImageFileName(); - QTest::newRow(QTest::toString(id + " url with path")) + QTest::addRow("%s url with path", id) << "image://test/test/path" + fileName << "test/path" + fileName << "" << QSize(100,100) << ""; fileName = newImageFileName(); - QTest::newRow(QTest::toString(id + " url with fragment")) + QTest::addRow("%s url with fragment", id) << "image://test/faq.html?#question13" + fileName << "faq.html?#question13" + fileName << "" << QSize(100,100) << ""; fileName = newImageFileName(); - QTest::newRow(QTest::toString(id + " url with query")) + QTest::addRow("%s url with query", id) << "image://test/cgi-bin/drawgraph.cgi?type=pie&color=green" + fileName << "cgi-bin/drawgraph.cgi?type=pie&color=green" + fileName << "" << QSize(100,100) << ""; fileName = newImageFileName(); - QTest::newRow(QTest::toString(id + " scaled image")) + QTest::addRow("%s scaled image", id) << "image://test/" + fileName << fileName << "sourceSize: \"80x30\"" << QSize(80,30) << ""; - QTest::newRow(QTest::toString(id + " missing")) + QTest::addRow("%s missing", id) << "image://test/no-such-file.png" << "no-such-file.png" << "" << QSize(100,100) << ":2:1: QML Image: Failed to get image from provider: image://test/no-such-file.png"; - QTest::newRow(QTest::toString(id + " unknown provider")) + QTest::addRow("%s unknown provider", id) << "image://bogus/exists.png" << "" << "" << QSize() << ":2:1: QML Image: Invalid image provider: image://bogus/exists.png"; } -- cgit v1.2.3 From c64d07218673a0ef951326650b12f3cb05cee4e4 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 15 Dec 2021 09:43:47 +0100 Subject: icutils::Node: GCC 11 -Werror=maybe-uninitialized w/-fsanitize=undefined MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The quint32_le_bitfield class, like its underlying type, doesn't provide a user-defined constructor, so default-construction leaves the 'val' member uninitialized. When the user-defined assignment operator then tries to read from 'val', that is undefined behavior. Or would, if vector::resize() wouldn't value-initialize, which it is required to do. So, False Positive, but due to -Werror, we need to do something about it (value-initialize the largest union member before calling assignment). Says GCC 11 with -stc=c++20 -fsanitize=undefined -Werror: In member function ‘QSpecialIntegerBitfield& QSpecialIntegerBitfield::operator=(QSpecialIntegerBitfield::T) [with S = QLittleEndianStorageType; int pos = 0; int width = 30]’, inlined from ‘icutils::Node::Node(std::vector::size_type)’ at qt5-build/qtbase/include/QtQml/6.3.0/QtQml/private/../../../../../../../qt5/qtdeclarative/src/qml/inlinecomponentutils_p.h:66:26, inlined from ‘constexpr void std::iota(_ForwardIterator, _ForwardIterator, _Tp) [with _ForwardIterator = __gnu_cxx::__normal_iterator >; _Tp = int]’ at /d/gcc/11/include/c++/11.2.1/bits/stl_numeric.h:99:4, inlined from ‘void QV4::ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate*, CompositeMetaTypeIds)’ at qt5/qtdeclarative/src/qml/jsruntime/qv4executablecompilationunit.cpp:444:14: qt5-build/qtbase/include/QtCore/6.3.0/QtCore/private/../../../../../../../qt5/qtbase/src/corelib/global/qendian_p.h:78:30: warning: ‘*(QSpecialIntegerBitfield, 0, 30>*)((char*)& + offsetof(icutils::Node, icutils::Node::)).QSpecialIntegerBitfield, 0, 30>::val’ may be used uninitialized [-Wmaybe-uninitialized] 78 | UT i = S::fromSpecial(val); | ~~~~~~~~~~~~~~^~~~~ In file included from /d/gcc/11/include/c++/11.2.1/numeric:62, from qt5/qtbase/src/corelib/tools/qhashfunctions.h:47, from qt5-build/qtbase/include/QtCore/qhashfunctions.h:1, from qt5/qtbase/src/corelib/tools/qlist.h:46, from qt5-build/qtbase/include/QtCore/qlist.h:1, from qt5/qtbase/src/corelib/kernel/qobject.h:49, from qt5-build/qtbase/include/QtCore/qobject.h:1, from qt5/qtbase/src/corelib/animation/qabstractanimation.h:43, from qt5-build/qtbase/include/QtCore/qabstractanimation.h:1, from qt5-build/qtbase/include/QtCore/QtCore:9, from qt5-build/qtdeclarative/src/qml/CMakeFiles/Qml.dir/cmake_pch.hxx:5, from : /d/gcc/11/include/c++/11.2.1/bits/stl_numeric.h: In member function ‘void QV4::ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate*, CompositeMetaTypeIds)’: /d/gcc/11/include/c++/11.2.1/bits/stl_numeric.h:99:20: note: ‘’ declared here 99 | *__first = __value; | ~~~~~~~~~^~~~~~~~~ Change-Id: I8bbe32438489120bd005e115ea34cd816c898116 Reviewed-by: Fabian Kosmale Reviewed-by: Thiago Macieira (cherry picked from commit cf60baa44f33377c8bd3bfd4273883ac5c129d54) Reviewed-by: Qt Cherry-pick Bot --- src/qml/inlinecomponentutils_p.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/qml/inlinecomponentutils_p.h b/src/qml/inlinecomponentutils_p.h index 0645d23fb1..eade87746e 100644 --- a/src/qml/inlinecomponentutils_p.h +++ b/src/qml/inlinecomponentutils_p.h @@ -62,7 +62,9 @@ struct Node { Node& operator=(Node &&) = default; bool operator==(Node const &other) const {return index == other.index;} - Node(std::vector::size_type s) { + Node(std::vector::size_type s) + : index{0} + { index = quint32(s); temporaryMark = 0; permanentMark = 0; -- cgit v1.2.3 From 9e43903f181c0809b7d6d1492991cc9a6a1f1e1c Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Mon, 29 Nov 2021 15:04:02 +0100 Subject: Doc: fix incorrect type name on focus page Change-Id: I32b8d8315c6dc1fa9d77c6cd052f74426adef46b Reviewed-by: Fabian Kosmale (cherry picked from commit c91de5e7814d83de0f4a6b4b48ba49299f490391) Reviewed-by: Qt Cherry-pick Bot --- src/quick/doc/src/concepts/input/focus.qdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quick/doc/src/concepts/input/focus.qdoc b/src/quick/doc/src/concepts/input/focus.qdoc index 9862489f42..21f5f0e225 100644 --- a/src/quick/doc/src/concepts/input/focus.qdoc +++ b/src/quick/doc/src/concepts/input/focus.qdoc @@ -196,7 +196,7 @@ property. As the \l ListView is a focus scope, this doesn't affect the rest of the application. However, if the \l ListView itself has active focus this causes the delegate itself to receive active focus. In this example, the root type of the delegate is also a focus scope, -which in turn gives active focus to the \c {Text} type that actually performs +which in turn gives active focus to the \l {TextInput} type that actually performs the work of handling the \c {Return} key. All of the QML view classes, such as \l PathView and \l GridView, behave -- cgit v1.2.3 From af72f30b057c867bea2569e968909c7cc23be43e Mon Sep 17 00:00:00 2001 From: Ivan Tkachenko Date: Thu, 9 Dec 2021 01:23:32 +0300 Subject: Doc: Fix QtQuick::Loader::item type QtObject, not an Item, because it can load from all sorts of components. Change-Id: If152ffa325433b928e61ab8c7eeea8b6f5992322 Reviewed-by: Paul Wicking Reviewed-by: Fabian Kosmale (cherry picked from commit 3c05e01dc502802c6118b0ac854c0208028875f3) Reviewed-by: Qt Cherry-pick Bot --- src/quick/items/qquickloader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp index 88f8af81d2..93cff95b7b 100644 --- a/src/quick/items/qquickloader.cpp +++ b/src/quick/items/qquickloader.cpp @@ -946,7 +946,7 @@ void QQuickLoaderPrivate::_q_updateSize(bool loaderGeometryChanged) } /*! - \qmlproperty object QtQuick::Loader::item + \qmlproperty QtObject QtQuick::Loader::item This property holds the top-level object that is currently loaded. Since \c {QtQuick 2.0}, Loader can load any object type. -- cgit v1.2.3 From e25c25453c05915c7cc70c434235a7daa9a27ff3 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Wed, 17 Nov 2021 12:12:57 +0100 Subject: Instantiator: Do not load items when inactive Instantiator would react to model changes even when inactive, causing instances to be errorneously created. We simply skip doing anything when inactive, as setting the Instantiator to active later will trigger a full regenaration anyway. Fixes: QTBUG-86453 Fixes: QTBUG-88331 Change-Id: Ia5fd916bbd591d5fc72c550424b1a53a142c2fa8 Reviewed-by: Maximilian Goldstein Reviewed-by: Ulf Hermann (cherry picked from commit a1c1ad11ce6f4a415cefc583cfab41336ecf71e3) Reviewed-by: Qt Cherry-pick Bot --- src/qmlmodels/qqmlinstantiator.cpp | 2 +- .../data/activeModelChangeInteraction.qml | 39 ++++++++++++++++++++++ .../qml/qqmlinstantiator/tst_qqmlinstantiator.cpp | 21 ++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 tests/auto/qml/qqmlinstantiator/data/activeModelChangeInteraction.qml diff --git a/src/qmlmodels/qqmlinstantiator.cpp b/src/qmlmodels/qqmlinstantiator.cpp index ffe62f174a..ea5a07b877 100644 --- a/src/qmlmodels/qqmlinstantiator.cpp +++ b/src/qmlmodels/qqmlinstantiator.cpp @@ -147,7 +147,7 @@ void QQmlInstantiatorPrivate::_q_modelUpdated(const QQmlChangeSet &changeSet, bo { Q_Q(QQmlInstantiator); - if (!componentComplete || effectiveReset) + if (!componentComplete || effectiveReset || !active) return; if (reset) { diff --git a/tests/auto/qml/qqmlinstantiator/data/activeModelChangeInteraction.qml b/tests/auto/qml/qqmlinstantiator/data/activeModelChangeInteraction.qml new file mode 100644 index 0000000000..2797566ad2 --- /dev/null +++ b/tests/auto/qml/qqmlinstantiator/data/activeModelChangeInteraction.qml @@ -0,0 +1,39 @@ +import QtQuick 2.15 +import QtQml.Models 2.15 + +Item { + id: root + property int instanceCount: 0 + property alias active: instantiator.active + + ListModel { + id: listmodel + + dynamicRoles: true + } + + Component.onCompleted: { + listmodel.insert(listmodel.count, {name: "one"}) + listmodel.insert(listmodel.count, {name: "two"}) + listmodel.insert(listmodel.count, {name: "three"}) + } + + Instantiator { + id: instantiator + + active: false + + model: listmodel + + delegate: Text { + width: 100 + height: 20 + + text: name + + Component.onCompleted: ++root.instanceCount + } + + } +} + diff --git a/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp b/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp index 84e08c471a..d5587432de 100644 --- a/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp +++ b/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp @@ -47,6 +47,7 @@ private slots: void createMultiple(); void stringModel(); void activeProperty(); + void activeModelChangeInteraction(); void intModelChange(); void createAndRemove(); @@ -153,6 +154,26 @@ void tst_qqmlinstantiator::activeProperty() QCOMPARE(object->property("idx").toInt(), 0); } +void tst_qqmlinstantiator::activeModelChangeInteraction() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("activeModelChangeInteraction.qml")); + QScopedPointer root(component.create()); + QVERIFY(root); + + // If the instantiator is inactive, a model change does not lead to items being loaded + bool ok = false; + int count = root->property("instanceCount").toInt(&ok); + QVERIFY(ok); + QCOMPARE(count, 0); + + // When turning the instantiator active, it will however reflect the model + root->setProperty("active", true); + count = root->property("instanceCount").toInt(&ok); + QVERIFY(ok); + QCOMPARE(count, 3); +} + void tst_qqmlinstantiator::intModelChange() { QQmlEngine engine; -- cgit v1.2.3 From 77eadd5f2236d4eed9b5de513494f96b1079be5a Mon Sep 17 00:00:00 2001 From: Ivan Tkachenko Date: Mon, 22 Nov 2021 05:16:56 +0300 Subject: doc: Fix QQuickItem point/rect mapping methods signatures Change-Id: I103de6db35fe34d7d9a334f421f75d6388a01fc6 Reviewed-by: Ulf Hermann (cherry picked from commit 4b3d2e77824cfee5e4c31ce58e90c7bf83c8e235) Reviewed-by: Qt Cherry-pick Bot --- src/quick/items/qquickitem.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 5454a8a69c..0363c16f7c 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -4543,10 +4543,10 @@ static bool unwrapMapFromToFromItemArgs(QQmlV4Function *args, const QQuickItem * } /*! - \qmlmethod object QtQuick::Item::mapFromItem(Item item, real x, real y) - \qmlmethod object QtQuick::Item::mapFromItem(Item item, point p) - \qmlmethod object QtQuick::Item::mapFromItem(Item item, real x, real y, real width, real height) - \qmlmethod object QtQuick::Item::mapFromItem(Item item, rect r) + \qmlmethod point QtQuick::Item::mapFromItem(Item item, real x, real y) + \qmlmethod point QtQuick::Item::mapFromItem(Item item, point p) + \qmlmethod rect QtQuick::Item::mapFromItem(Item item, real x, real y, real width, real height) + \qmlmethod rect QtQuick::Item::mapFromItem(Item item, rect r) Maps the point (\a x, \a y) or rect (\a x, \a y, \a width, \a height), which is in \a item's coordinate system, to this item's coordinate system, and returns a \l point or \l rect @@ -4598,10 +4598,10 @@ QTransform QQuickItem::itemTransform(QQuickItem *other, bool *ok) const } /*! - \qmlmethod object QtQuick::Item::mapToItem(Item item, real x, real y) - \qmlmethod object QtQuick::Item::mapToItem(Item item, point p) - \qmlmethod object QtQuick::Item::mapToItem(Item item, real x, real y, real width, real height) - \qmlmethod object QtQuick::Item::mapToItem(Item item, rect r) + \qmlmethod point QtQuick::Item::mapToItem(Item item, real x, real y) + \qmlmethod point QtQuick::Item::mapToItem(Item item, point p) + \qmlmethod rect QtQuick::Item::mapToItem(Item item, real x, real y, real width, real height) + \qmlmethod rect QtQuick::Item::mapToItem(Item item, rect r) Maps the point (\a x, \a y) or rect (\a x, \a y, \a width, \a height), which is in this item's coordinate system, to \a item's coordinate system, and returns a \l point or \l rect @@ -4683,7 +4683,7 @@ static bool unwrapMapFromToFromGlobalArgs(QQmlV4Function *args, const QQuickItem /*! \since 5.7 - \qmlmethod object QtQuick::Item::mapFromGlobal(real x, real y) + \qmlmethod point QtQuick::Item::mapFromGlobal(real x, real y) Maps the point (\a x, \a y), which is in the global coordinate system, to the item's coordinate system, and returns a \l point matching the mapped coordinate. @@ -4710,7 +4710,7 @@ void QQuickItem::mapFromGlobal(QQmlV4Function *args) const /*! \since 5.7 - \qmlmethod object QtQuick::Item::mapToGlobal(real x, real y) + \qmlmethod point QtQuick::Item::mapToGlobal(real x, real y) Maps the point (\a x, \a y), which is in this item's coordinate system, to the global coordinate system, and returns a \l point matching the mapped coordinate. -- cgit v1.2.3 From 501979c2e44de1d3823800f7f758708e39b94ac6 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 3 Feb 2022 10:02:06 +0100 Subject: V4: Do not call dtor of an object we continue to use After destroyObject(), the QObjectWrapper is still alive. We might use its heap object again. Furthermore, the Heap::QObjectWrapper dtor does not actually do anything defined. What we want to do here is clear the QObject pointer because we've just gotten rid of the QObject. There is a method for that: Heap::QObjectWrapper::destroy(). Finally, the internalClass must never ever be nullptr. Assert on that rather than checking it. Task-number: QTBUG-100431 Change-Id: I794a295c182b2ed4ba80673f58d6143c861b7391 Reviewed-by: Andrei Golubev Reviewed-by: Qt CI Bot Reviewed-by: Fabian Kosmale (cherry picked from commit 6c197319f34b8098d034f1543eb5feb9d7be54c3) Reviewed-by: Qt Cherry-pick Bot --- src/qml/jsruntime/qv4qobjectwrapper.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 29780590b4..b9cb74c3ca 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -1145,8 +1145,7 @@ void Heap::QObjectWrapper::markObjects(Heap::Base *that, QV4::MarkStack *markSta void QObjectWrapper::destroyObject(bool lastCall) { Heap::QObjectWrapper *h = d(); - if (!h->internalClass) - return; // destroyObject already got called + Q_ASSERT(h->internalClass); if (h->object()) { QQmlData *ddata = QQmlData::get(h->object(), false); @@ -1176,7 +1175,7 @@ void QObjectWrapper::destroyObject(bool lastCall) } } - h->~Data(); + h->destroy(); } -- cgit v1.2.3 From 9685937286cfccb8024019fab894cf5b11d233fe Mon Sep 17 00:00:00 2001 From: Ivan Tkachenko Date: Thu, 28 Oct 2021 02:49:23 +0300 Subject: Fix indentation in positioners example Change-Id: I5a39ba9361503cd5d7ce2e6da59d7807d540bee5 Reviewed-by: Paul Wicking (cherry picked from commit e4308747d3a27a5b942c5b79fcbb77f7b327ae67) Reviewed-by: Qt Cherry-pick Bot --- .../positioners/positioners-attachedproperties.qml | 28 +++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/examples/quick/positioners/positioners-attachedproperties.qml b/examples/quick/positioners/positioners-attachedproperties.qml index af89543289..38c71068f2 100644 --- a/examples/quick/positioners/positioners-attachedproperties.qml +++ b/examples/quick/positioners/positioners-attachedproperties.qml @@ -90,14 +90,14 @@ Rectangle { anchors.leftMargin: 20 anchors.verticalCenter: parent.verticalCenter text: "Index: " + parent.Positioner.index - + (parent.Positioner.isFirstItem ? " (First)" : "") - + (parent.Positioner.isLastItem ? " (Last)" : "") + + (parent.Positioner.isFirstItem ? " (First)" : "") + + (parent.Positioner.isLastItem ? " (Last)" : "") } // When mouse is clicked, display the values of the positioner MouseArea { - anchors.fill: parent - onClicked: column.showInfo(green.Positioner) + anchors.fill: parent + onClicked: column.showInfo(green.Positioner) } } //! [0] @@ -113,14 +113,14 @@ Rectangle { anchors.leftMargin: 20 anchors.verticalCenter: parent.verticalCenter text: "Index: " + parent.Positioner.index - + (parent.Positioner.isFirstItem ? " (First)" : "") - + (parent.Positioner.isLastItem ? " (Last)" : "") + + (parent.Positioner.isFirstItem ? " (First)" : "") + + (parent.Positioner.isLastItem ? " (Last)" : "") } // When mouse is clicked, display the values of the positioner MouseArea { - anchors.fill: parent - onClicked: column.showInfo(blue.Positioner) + anchors.fill: parent + onClicked: column.showInfo(blue.Positioner) } } @@ -135,14 +135,14 @@ Rectangle { anchors.leftMargin: 20 anchors.verticalCenter: parent.verticalCenter text: "Index: " + parent.Positioner.index - + (parent.Positioner.isFirstItem ? " (First)" : "") - + (parent.Positioner.isLastItem ? " (Last)" : "") + + (parent.Positioner.isFirstItem ? " (First)" : "") + + (parent.Positioner.isLastItem ? " (Last)" : "") } // When mouse is clicked, display the values of the positioner MouseArea { - anchors.fill: parent - onClicked: column.showInfo(purple.Positioner) + anchors.fill: parent + onClicked: column.showInfo(purple.Positioner) } } @@ -159,8 +159,8 @@ Rectangle { anchors.leftMargin: 20 anchors.verticalCenter: parent.verticalCenter text: "Index: " + parent.Positioner.index - + (parent.Positioner.isFirstItem ? " (First)" : "") - + (parent.Positioner.isLastItem ? " (Last)" : "") + + (parent.Positioner.isFirstItem ? " (First)" : "") + + (parent.Positioner.isLastItem ? " (Last)" : "") } } -- cgit v1.2.3 From 8fb6916ee438b2068645c24d861e8cbfad84718d Mon Sep 17 00:00:00 2001 From: Hatem ElKharashy Date: Mon, 24 Jan 2022 15:07:01 +0200 Subject: Fix indices alignment problem The buffer that holds the data is now 4 byte aligned in case of the usage of shared buffer for vertices and indices. Fixes: QTBUG-83315 Change-Id: I8b1c11c7cf0d4ca052fbaaa749828d28589fc297 Reviewed-by: Laszlo Agocs --- src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index a749e1c92b..a6c07d5964 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -2215,6 +2215,15 @@ void Renderer::uploadBatch(Batch *b) */ int bufferSize = b->vertexCount * g->sizeOfVertex(); int ibufferSize = 0; + // At this point, we need to check if the vertices byte size is 4 byte aligned or not. + // If an unaligned value is used in a shared buffer with indices, it causes problems with + // glDrawElements. We need to do a 4 byte alignment so that it can work with both + // QSGGeometry::UnsignedShortType and QSGGeometry::UnsignedIntType + int paddingBytes = 0; + if (!m_context->separateIndexBuffer()) { + paddingBytes = aligned(bufferSize, 4) - bufferSize; + bufferSize += paddingBytes; + } if (b->merged) { ibufferSize = b->indexCount * mergedIndexElemSize(); if (m_useDepthBuffer) @@ -2239,7 +2248,7 @@ void Renderer::uploadBatch(Batch *b) char *zData = vertexData + b->vertexCount * g->sizeOfVertex(); char *indexData = separateIndexBuffer ? b->ibo.data - : zData + (int(m_useDepthBuffer) * b->vertexCount * sizeof(float)); + : zData + (int(m_useDepthBuffer) * b->vertexCount * sizeof(float)) + paddingBytes; quint16 iOffset16 = 0; quint32 iOffset32 = 0; @@ -2287,7 +2296,7 @@ void Renderer::uploadBatch(Batch *b) } else { char *vboData = b->vbo.data; char *iboData = separateIndexBuffer ? b->ibo.data - : vboData + b->vertexCount * g->sizeOfVertex(); + : vboData + b->vertexCount * g->sizeOfVertex() + paddingBytes; Element *e = b->first; while (e) { QSGGeometry *g = e->node->geometry(); @@ -3176,8 +3185,14 @@ void Renderer::renderUnmergedBatch(const Batch *batch) // legacy (GL-only) int vOffset = 0; char *iOffset = indexBase; + // If a shared buffer is used, 4 byte alignment was done to avoid issues + // while using glDrawElements with both QSGGeometry::UnsignedShortType and + // QSGGeometry::UnsignedIntType. Here, we need to take this into account + // while calculating iOffset value to end up with the correct offset for drawing. + int vertexDataByteSize = batch->vertexCount * gn->geometry()->sizeOfVertex(); + vertexDataByteSize = aligned(vertexDataByteSize, 4); if (!separateIndexBuffer) - iOffset += batch->vertexCount * gn->geometry()->sizeOfVertex(); + iOffset += vertexDataByteSize; QMatrix4x4 rootMatrix = batch->root ? qsg_matrixForRoot(batch->root) : QMatrix4x4(); -- cgit v1.2.3 From d4d0530317d724db650e553fa7463601b601a4c0 Mon Sep 17 00:00:00 2001 From: Alexandru Croitor Date: Mon, 7 Feb 2022 15:15:46 +0100 Subject: CMake: Skip qtquickcompiler cmake test on macOS ARM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It errors out with RCC Parse Error: 'build/qtquickcompiler/empty_qmlcache.qrc' Line: 1 Column: 0 [Premature end of document.] Task-number: QTBUG-99362 Change-Id: Ife0a0bc3e31b891e53b96dddee2c7a26a16d4c20 Reviewed-by: Tor Arne Vestbø --- tests/auto/cmake/CMakeLists.txt | 25 ++++++++++++++----------- tests/auto/cmake/cmake.pro | 4 ++++ 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/tests/auto/cmake/CMakeLists.txt b/tests/auto/cmake/CMakeLists.txt index bda5d626a9..55a59f3d55 100644 --- a/tests/auto/cmake/CMakeLists.txt +++ b/tests/auto/cmake/CMakeLists.txt @@ -16,17 +16,20 @@ test_module_includes( expect_pass(test_plugins) -add_test(qtquickcompiler ${CMAKE_CTEST_COMMAND} - --build-and-test - "${CMAKE_CURRENT_SOURCE_DIR}/qtquickcompiler/" - "${CMAKE_CURRENT_BINARY_DIR}/qtquickcompiler" - --build-config "${CMAKE_BUILD_TYPE}" - --build-generator ${CMAKE_GENERATOR} - --build-makeprogram ${CMAKE_MAKE_PROGRAM} - --build-project qqc_test - --build-options "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}" ${BUILD_OPTIONS_LIST} - --test-command qqc_test -) +# RCC fails to run, see QTBUG-99362 +if(NOT QT_SKIP_MACOS_ARM_TESTS) + add_test(qtquickcompiler ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMAKE_CURRENT_SOURCE_DIR}/qtquickcompiler/" + "${CMAKE_CURRENT_BINARY_DIR}/qtquickcompiler" + --build-config "${CMAKE_BUILD_TYPE}" + --build-generator ${CMAKE_GENERATOR} + --build-makeprogram ${CMAKE_MAKE_PROGRAM} + --build-project qqc_test + --build-options "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}" ${BUILD_OPTIONS_LIST} + --test-command qqc_test + ) +endif() add_test(qmlimportscanner ${CMAKE_CTEST_COMMAND} --build-and-test diff --git a/tests/auto/cmake/cmake.pro b/tests/auto/cmake/cmake.pro index 0a5e7e75fc..6c0e23306e 100644 --- a/tests/auto/cmake/cmake.pro +++ b/tests/auto/cmake/cmake.pro @@ -5,3 +5,7 @@ TEMPLATE = subdirs CMAKE_QT_MODULES_UNDER_TEST = quick qml CONFIG += ctest_testcase + +macos:contains(QT_ARCHS, arm64) { + CMAKE_MODULE_DEFINES += -DQT_SKIP_MACOS_ARM_TESTS=1 +} -- cgit v1.2.3 From 1f4b5760031bc0d2e090e0f76237a9477cebc65d Mon Sep 17 00:00:00 2001 From: Alexandru Croitor Date: Mon, 7 Feb 2022 15:54:54 +0100 Subject: CMake: Fix handling of empty qrc files with qtquickcompiler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't run rcc on empty qrc files. If the output of running rcc --list at configure time was empty, than we shouldn't call qt5_add_resources on the list of filetered rcc files because they will also be empty. Revert the maOS ARM skipping of the test now that the underlying issue is fixed. As a drive-by, fix main.qml file size check in main.cpp. If the file is successfully embedded, it shouldn't have a 0 size. Amends eb1f9c2e687002643ebc80e51d4bfc5f0258da0d Task-number: QTBUG-99362 Change-Id: I57dfaf1edbe5b26d051aed604703b2c7640dc4e2 Reviewed-by: Tor Arne Vestbø --- tests/auto/cmake/CMakeLists.txt | 25 ++++++++++------------- tests/auto/cmake/cmake.pro | 4 ---- tests/auto/cmake/qtquickcompiler/main.cpp | 2 +- tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in | 11 +++++++--- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/tests/auto/cmake/CMakeLists.txt b/tests/auto/cmake/CMakeLists.txt index 55a59f3d55..bda5d626a9 100644 --- a/tests/auto/cmake/CMakeLists.txt +++ b/tests/auto/cmake/CMakeLists.txt @@ -16,20 +16,17 @@ test_module_includes( expect_pass(test_plugins) -# RCC fails to run, see QTBUG-99362 -if(NOT QT_SKIP_MACOS_ARM_TESTS) - add_test(qtquickcompiler ${CMAKE_CTEST_COMMAND} - --build-and-test - "${CMAKE_CURRENT_SOURCE_DIR}/qtquickcompiler/" - "${CMAKE_CURRENT_BINARY_DIR}/qtquickcompiler" - --build-config "${CMAKE_BUILD_TYPE}" - --build-generator ${CMAKE_GENERATOR} - --build-makeprogram ${CMAKE_MAKE_PROGRAM} - --build-project qqc_test - --build-options "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}" ${BUILD_OPTIONS_LIST} - --test-command qqc_test - ) -endif() +add_test(qtquickcompiler ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMAKE_CURRENT_SOURCE_DIR}/qtquickcompiler/" + "${CMAKE_CURRENT_BINARY_DIR}/qtquickcompiler" + --build-config "${CMAKE_BUILD_TYPE}" + --build-generator ${CMAKE_GENERATOR} + --build-makeprogram ${CMAKE_MAKE_PROGRAM} + --build-project qqc_test + --build-options "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}" ${BUILD_OPTIONS_LIST} + --test-command qqc_test +) add_test(qmlimportscanner ${CMAKE_CTEST_COMMAND} --build-and-test diff --git a/tests/auto/cmake/cmake.pro b/tests/auto/cmake/cmake.pro index 6c0e23306e..0a5e7e75fc 100644 --- a/tests/auto/cmake/cmake.pro +++ b/tests/auto/cmake/cmake.pro @@ -5,7 +5,3 @@ TEMPLATE = subdirs CMAKE_QT_MODULES_UNDER_TEST = quick qml CONFIG += ctest_testcase - -macos:contains(QT_ARCHS, arm64) { - CMAKE_MODULE_DEFINES += -DQT_SKIP_MACOS_ARM_TESTS=1 -} diff --git a/tests/auto/cmake/qtquickcompiler/main.cpp b/tests/auto/cmake/qtquickcompiler/main.cpp index c357ef60e6..680f81755d 100644 --- a/tests/auto/cmake/qtquickcompiler/main.cpp +++ b/tests/auto/cmake/qtquickcompiler/main.cpp @@ -13,7 +13,7 @@ private slots: void tst_QQC::packaging() { QVERIFY(QFile::exists(":/main.qml")); - QCOMPARE(QFileInfo(":/main.qml").size(), 0); + QVERIFY(QFileInfo(":/main.qml").size() > 0); QVERIFY(QFile::exists(":/main.cpp")); QVERIFY(QFileInfo(":/main.cpp").size() > 0); diff --git a/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in b/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in index 26d42c02a9..8a91fb8b87 100644 --- a/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in +++ b/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in @@ -40,6 +40,7 @@ but not all the files it references. set(rcc_files ${_RCC_UNPARSED_ARGUMENTS}) set(rcc_options ${_RCC_OPTIONS}) set(filtered_rcc_files) + set(output_resources) set(compiler_output) set(rcc_files_with_compilation_units) set(loader_flags) @@ -52,13 +53,15 @@ but not all the files it references. set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${input_resource}") execute_process(COMMAND ${compiler_path} --filter-resource-file ${input_resource} -o ${new_resource_file} OUTPUT_VARIABLE remaining_files) - list(APPEND filtered_rcc_files ${new_resource_file}) - list(APPEND loader_flags \"--resource-file-mapping=${_resource}=${new_resource_file}\") set(rcc_file_with_compilation_units) execute_process(COMMAND ${rcc_path} -list \"${input_resource}\" OUTPUT_VARIABLE rcc_contents) if (NOT rcc_contents STREQUAL \"\") + + list(APPEND filtered_rcc_files ${new_resource_file}) + list(APPEND loader_flags \"--resource-file-mapping=${_resource}=${new_resource_file}\") + string(REGEX REPLACE \"[\r\n]+\" \";\" rcc_contents ${rcc_contents}) foreach(it ${rcc_contents}) get_filename_component(extension ${it} EXT) @@ -85,6 +88,8 @@ but not all the files it references. list(APPEND compiler_output ${loader_source}) endif() - qt5_add_resources(output_resources ${filtered_rcc_files} OPTIONS ${rcc_options}) + if(filtered_rcc_files) + qt5_add_resources(output_resources ${filtered_rcc_files} OPTIONS ${rcc_options}) + endif() set(${outfiles} ${output_resources} ${compiler_output} PARENT_SCOPE) endfunction() -- cgit v1.2.3 From 1b65829d3ab342230eb13493cefce0cd6c93ed79 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Mon, 7 Feb 2022 15:48:30 +0100 Subject: Correctly handle QQuickState::when 64c1fbe96c68b1286a70242ff4922be140128cb2 fixed that one could not assign a constant value to QQuickState::when. However, as alluded to by a comment in QQState's code, this caused state oscillation, breaking clean transitions between two states. The reason for this issue is that as soon as once of the when condition changes, we check the when condition of all states. However, in the case of logically exclusive cases we can run into the issue that the binding of the second state has not been re-evaluated yet. Thus, we might end up with all states being false, even though the second one becomes true immediately afterwards. To avoid this issue, we force the reevaluation of the binding. However, instead of doing this by using a QQmlBinding property (with all the tooling and runtime issues that it would entail), we keep using a normal property. We then ask the engine for the binding, and if it exists, we reevaluate it to obtain the current value. Fixes: QTBUG-86695 Change-Id: Id10a3549935794b93b29450b0f5dfb6d1df691a1 Reviewed-by: Ulf Hermann (cherry picked from commit a8c729d83979fb0b9939044d246e73b1d578e65b) Reviewed-by: Qt CI Bot Reviewed-by: Andrei Golubev --- src/quick/util/qquickstategroup.cpp | 9 ++++++++- .../qquickstates/data/noStateOsciallation.qml | 22 ++++++++++++++++++++++ tests/auto/quick/qquickstates/tst_qquickstates.cpp | 15 +++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 tests/auto/quick/qquickstates/data/noStateOsciallation.qml diff --git a/src/quick/util/qquickstategroup.cpp b/src/quick/util/qquickstategroup.cpp index cd4c0a320b..f2af12b81d 100644 --- a/src/quick/util/qquickstategroup.cpp +++ b/src/quick/util/qquickstategroup.cpp @@ -376,7 +376,14 @@ bool QQuickStateGroupPrivate::updateAutoState() QQuickState *state = states.at(ii); if (state->isWhenKnown()) { if (state->isNamed()) { - if (state->when()) { + bool whenValue = state->when(); + const QQmlProperty whenProp(state, QLatin1String("when")); + const auto potentialWhenBinding = QQmlPropertyPrivate::binding(whenProp); + // if there is a binding, the value in when might not be up-to-date at this point + // so we manually reevaluate the binding + if (auto abstractBinding = dynamic_cast(potentialWhenBinding)) + whenValue = abstractBinding->evaluate().toBool(); + if (whenValue) { if (stateChangeDebug()) qWarning() << "Setting auto state due to expression"; if (currentState != state->name()) { diff --git a/tests/auto/quick/qquickstates/data/noStateOsciallation.qml b/tests/auto/quick/qquickstates/data/noStateOsciallation.qml new file mode 100644 index 0000000000..f0d7aeeb6d --- /dev/null +++ b/tests/auto/quick/qquickstates/data/noStateOsciallation.qml @@ -0,0 +1,22 @@ +import QtQuick 2.15 + +Item { + id: root + property int number: 2 + property int stateChangeCounter: 0 + + Item { + id: item + onStateChanged: ++stateChangeCounter + states: [ + State { + name: "n1" + when: root.number === 1 + }, + State { + name: "n2" + when: root.number === 2 + } + ] + } +} diff --git a/tests/auto/quick/qquickstates/tst_qquickstates.cpp b/tests/auto/quick/qquickstates/tst_qquickstates.cpp index 849522454f..aa55b42935 100644 --- a/tests/auto/quick/qquickstates/tst_qquickstates.cpp +++ b/tests/auto/quick/qquickstates/tst_qquickstates.cpp @@ -188,6 +188,7 @@ private slots: void revertListMemoryLeak(); void duplicateStateName(); void trivialWhen(); + void noStateOsciallation(); void parentChangeCorrectReversal(); void revertNullObjectBinding(); }; @@ -1733,6 +1734,20 @@ void tst_qquickstates::trivialWhen() QVERIFY(c.create()); } +void tst_qquickstates::noStateOsciallation() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("noStateOsciallation.qml")); + QScopedPointer root {component.create()}; + QVERIFY(root); + // set to 1 on initial transition from "" to "n2" + QCOMPARE(root->property("stateChangeCounter").toInt(), 1); + root->setProperty("number", 1); + // setting number to 1 changes directly from "n2" to "n1" + // without any intermediate transition to "" + QCOMPARE(root->property("stateChangeCounter").toInt(), 2); +} + void tst_qquickstates::parentChangeCorrectReversal() { QQmlEngine engine; -- cgit v1.2.3 From 2ce8a33347e827fa4a1579b937ff5bbbadc16451 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Mon, 31 Jan 2022 14:14:26 +0100 Subject: QQmlAdaptorModel: Do not use reparenting for lifetime managemment In QQmlAdaptorModel, we were using QQmlStrongJSQObjectReference to ensure that a passed in model lives long enough. However, QQmlAdaptorModel uses reparenting to keep objects alive. This is not safe, as we can use QML singletons as models. Reparenting singletons messes with the engine's lifetime handling once their new parent gets deleted: The object will be marked as queuedForDeletion by QQmlData::markAsDeleted; consequently wasDeleted returns true for the object, and any ScopedObject or ObjectWrapper will return nullptr when we try to retrieve their underlying QObject. The actual object probaly does not get deleted, as it is not placed in the QML heap. Consequently the gc will ignore it. This leads to a crash when the singleton is accessed in a different place: We see that the object is non-null, create a ScopedObject for it, and then try to later access the ScopedObject's underlying object (assuming that it must be non-null, because we already checked for the actual object being non-null). However, due to the reasons outlined above, we actually receive a null pointer, and thus encounter a crash. To avoid he issue, we change the lifetime management strategy: Instead of using the parent to keep the object alive, we now use a QV4::PersistentValue. Fixes: QTBUG-100260 Change-Id: I266e6ef94c4f079de3da2742d6fb8d61df5a64ce Reviewed-by: Andrei Golubev Reviewed-by: Ulf Hermann (cherry picked from commit 6901eacff40a7d8781e20fb5bcfd28d7526b589b) (cherry picked from commit ce8db0672557cef7942df061f52ccdf65fa250f6) Reviewed-by: Qt CI Bot --- src/qmlmodels/qqmladaptormodel.cpp | 18 ++++++++---- src/qmlmodels/qqmladaptormodel_p.h | 6 +++- src/qmlmodels/qqmldelegatemodel.cpp | 2 +- .../qquicklistview/data/singletonModelLifetime.qml | 32 ++++++++++++++++++++++ .../quick/qquicklistview/tst_qquicklistview.cpp | 24 ++++++++++++++++ 5 files changed, 74 insertions(+), 8 deletions(-) create mode 100644 tests/auto/quick/qquicklistview/data/singletonModelLifetime.qml diff --git a/src/qmlmodels/qqmladaptormodel.cpp b/src/qmlmodels/qqmladaptormodel.cpp index f4dca6e518..b82a589788 100644 --- a/src/qmlmodels/qqmladaptormodel.cpp +++ b/src/qmlmodels/qqmladaptormodel.cpp @@ -962,30 +962,36 @@ QQmlAdaptorModel::~QQmlAdaptorModel() accessors->cleanup(*this); } -void QQmlAdaptorModel::setModel(const QVariant &variant, QObject *parent, QQmlEngine *engine) +void QQmlAdaptorModel::setModel(const QVariant &variant, QObject *, QQmlEngine *engine) { accessors->cleanup(*this); list.setList(variant, engine); + modelStrongReference.clear(); if (QObject *object = qvariant_cast(list.list())) { - setObject(object, parent); + if (QQmlData *ddata = QQmlData::get(object)) + modelStrongReference = ddata->jsWrapper; + setObject(object); if (qobject_cast(object)) accessors = new VDMAbstractItemModelDataType(this); else accessors = new VDMObjectDelegateDataType; } else if (list.type() == QQmlListAccessor::ListProperty) { - setObject(static_cast(variant.constData())->object(), parent); + auto object = static_cast(variant.constData())->object(); + if (QQmlData *ddata = QQmlData::get(object)) + modelStrongReference = ddata->jsWrapper; + setObject(object); accessors = new VDMObjectDelegateDataType; } else if (list.type() == QQmlListAccessor::ObjectList) { - setObject(nullptr, parent); + setObject(nullptr); accessors = new VDMObjectDelegateDataType; } else if (list.type() != QQmlListAccessor::Invalid && list.type() != QQmlListAccessor::Instance) { // Null QObject - setObject(nullptr, parent); + setObject(nullptr); accessors = new VDMListDelegateDataType; } else { - setObject(nullptr, parent); + setObject(nullptr); accessors = &qt_vdm_null_accessors; } } diff --git a/src/qmlmodels/qqmladaptormodel_p.h b/src/qmlmodels/qqmladaptormodel_p.h index 537ec65eed..4f01a37f0a 100644 --- a/src/qmlmodels/qqmladaptormodel_p.h +++ b/src/qmlmodels/qqmladaptormodel_p.h @@ -70,7 +70,7 @@ class QQmlDelegateModel; class QQmlDelegateModelItem; class QQmlDelegateModelItemMetaType; -class Q_QMLMODELS_PRIVATE_EXPORT QQmlAdaptorModel : public QQmlStrongJSQObjectReference +class Q_QMLMODELS_PRIVATE_EXPORT QQmlAdaptorModel : public QQmlGuard { public: class Accessors @@ -114,6 +114,10 @@ public: const Accessors *accessors; QPersistentModelIndex rootIndex; QQmlListAccessor list; + // we need to ensure that a JS created model does not get gced, but cannot + // arbitrarily set the parent (using QQmlStrongJSQObjectReference) of QObject based models, + // as that causes issues with singletons + QV4::PersistentValue modelStrongReference; int modelItemRevision = 0; diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp index 751d9e301e..8e9ca0ce55 100644 --- a/src/qmlmodels/qqmldelegatemodel.cpp +++ b/src/qmlmodels/qqmldelegatemodel.cpp @@ -258,7 +258,7 @@ QQmlDelegateModel::~QQmlDelegateModel() { Q_D(QQmlDelegateModel); d->disconnectFromAbstractItemModel(); - d->m_adaptorModel.setObject(nullptr, this); + d->m_adaptorModel.setObject(nullptr); for (QQmlDelegateModelItem *cacheItem : qAsConst(d->m_cache)) { if (cacheItem->object) { diff --git a/tests/auto/quick/qquicklistview/data/singletonModelLifetime.qml b/tests/auto/quick/qquicklistview/data/singletonModelLifetime.qml new file mode 100644 index 0000000000..f230786723 --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/singletonModelLifetime.qml @@ -0,0 +1,32 @@ +import QtQuick 2.15 +import QtQuick.Window 2.15 +import test 1.0 + +Window { + id: root + visible: true + width: 800 + height: 680 + property bool alive: false + + Component { + id: view + ListView { + model: SingletonModel + } + } + function compare(a,b) { + root.alive = (a === b) + } + + function test_singletonModelCrash() { + SingletonModel.objectName = "model" + var o = view.createObject(root) + o.destroy() + Qt.callLater(function() { + compare(SingletonModel.objectName, "model") + }) + } + + Component.onCompleted: root.test_singletonModelCrash() +} diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index d3deb513d0..7b17c014d5 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include #include #include @@ -302,6 +304,9 @@ private slots: void dragDelegateWithMouseArea(); void dragDelegateWithMouseArea_data(); + + void singletonModelLifetime(); + private: template void items(const QUrl &source); template void changed(const QUrl &source); @@ -10200,6 +10205,25 @@ void tst_QQuickListView::dragDelegateWithMouseArea_data() } } +class SingletonModel : public QStringListModel +{ + Q_OBJECT +public: + SingletonModel(QObject* parent = nullptr) : QStringListModel(parent) { } +}; + +void tst_QQuickListView::singletonModelLifetime() +{ + // this does not really test any functionality of listview, but we do not have a good way + // to unit test QQmlAdaptorModel in isolation. + qmlRegisterSingletonType("test", 1, 0, "SingletonModel", + [](QQmlEngine* , QJSEngine*) -> QObject* { return new SingletonModel; }); + + QQmlApplicationEngine engine(testFile("singletonModelLifetime.qml")); + // needs event loop iteration for callLater to execute + QTRY_VERIFY(engine.rootObjects().first()->property("alive").toBool()); +} + QTEST_MAIN(tst_QQuickListView) #include "tst_qquicklistview.moc" -- cgit v1.2.3 From 97cd99f74890c8a7689e7df0a873e0a133d5eb09 Mon Sep 17 00:00:00 2001 From: Heikki Halmet Date: Mon, 14 Feb 2022 10:13:52 +0200 Subject: Fix typo in qquickdroparea/BLACKLIST for Ubuntu-20.04 Task-number: QTBUG-99765 Change-Id: I54e7c335cdd8a3fea5336c0cfa8aa806f515e5c9 Reviewed-by: Tarja Sundqvist --- tests/auto/quick/qquickdroparea/BLACKLIST | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/quick/qquickdroparea/BLACKLIST b/tests/auto/quick/qquickdroparea/BLACKLIST index d5963a692b..0967969b04 100644 --- a/tests/auto/quick/qquickdroparea/BLACKLIST +++ b/tests/auto/quick/qquickdroparea/BLACKLIST @@ -1,4 +1,4 @@ # Blacklist for testing # QTBUG-99765 [containsDrag_internal] -ubuntu 20.04 +ubuntu-20.04 -- cgit v1.2.3 From 5b12df09acd6f6b94a6f6c2dda2be910005716d7 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 13 Jul 2021 15:49:40 +0200 Subject: Doc: add example snippets for containmentMask This shows how to use non-rectangular shapes for hit tests, as well as how to define the contains function in QML. Task-number: QTBUG-89380 Change-Id: I93c686d840b292816a788c05a0a76fafa338d5f8 Reviewed-by: Venugopal Shivashankar Reviewed-by: Mitch Curtis (cherry picked from commit 382d2bfe5f261c269ccf4b970c826003c90d57ae) Reviewed-by: Qt Cherry-pick Bot --- src/quick/doc/images/containmentMask-circle.gif | Bin 0 -> 9926 bytes src/quick/doc/images/containmentMask-shape.gif | Bin 0 -> 11261 bytes .../qml/item/containmentMask-circle-js.qml | 71 ++++++++++++++++++ .../snippets/qml/item/containmentMask-shape.qml | 80 +++++++++++++++++++++ src/quick/items/qquickitem.cpp | 24 +++++-- 5 files changed, 171 insertions(+), 4 deletions(-) create mode 100644 src/quick/doc/images/containmentMask-circle.gif create mode 100644 src/quick/doc/images/containmentMask-shape.gif create mode 100644 src/quick/doc/snippets/qml/item/containmentMask-circle-js.qml create mode 100644 src/quick/doc/snippets/qml/item/containmentMask-shape.qml diff --git a/src/quick/doc/images/containmentMask-circle.gif b/src/quick/doc/images/containmentMask-circle.gif new file mode 100644 index 0000000000..80abce625f Binary files /dev/null and b/src/quick/doc/images/containmentMask-circle.gif differ diff --git a/src/quick/doc/images/containmentMask-shape.gif b/src/quick/doc/images/containmentMask-shape.gif new file mode 100644 index 0000000000..e7989352eb Binary files /dev/null and b/src/quick/doc/images/containmentMask-shape.gif differ diff --git a/src/quick/doc/snippets/qml/item/containmentMask-circle-js.qml b/src/quick/doc/snippets/qml/item/containmentMask-circle-js.qml new file mode 100644 index 0000000000..2d97bcdafa --- /dev/null +++ b/src/quick/doc/snippets/qml/item/containmentMask-circle-js.qml @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation 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 QtQml 2.12 +import QtQuick 2.12 + +//![0] +Rectangle { + id: circle + width: 100; height: width + radius: width / 2 + color: tapHandler.pressed ? "tomato" : hoverHandler.hovered ? "darkgray" : "lightgray" + + TapHandler { id: tapHandler } + HoverHandler { id: hoverHandler } + + containmentMask: QtObject { + property alias radius: circle.radius + function contains(point: point) : bool { + return (Math.pow(point.x - radius, 2) + Math.pow(point.y - radius, 2)) < Math.pow(radius, 2) + } + } +} +//![0] diff --git a/src/quick/doc/snippets/qml/item/containmentMask-shape.qml b/src/quick/doc/snippets/qml/item/containmentMask-shape.qml new file mode 100644 index 0000000000..a3da217e73 --- /dev/null +++ b/src/quick/doc/snippets/qml/item/containmentMask-shape.qml @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation 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.12 +import QtQuick.Shapes 1.12 + +//![0] +Rectangle { + width: 90; height: 100 + color: hoverHandler.hovered ? "wheat" : "lightgray" + containmentMask: shape + + HoverHandler { id: hoverHandler } + + Shape { + id: shape + containsMode: Shape.FillContains + + ShapePath { + fillColor: "lightsteelblue" + startX: 10; startY: 20 + PathArc { + x: 10; y: 80 + radiusX: 40; radiusY: 40 + useLargeArc: true + } + PathLine { + x: 10; y: 20 + } + } + } +} +//![0] diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 0363c16f7c..58b7da4b6a 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -7887,10 +7887,26 @@ bool QQuickItem::contains(const QPointF &point) const \e{item}'s contains method would then return \c true only if \e{anotherItem}'s contains() implementation returns \c true. - A \l Shape can be used in this way, to make an item react to - \l {QPointerEvent}{pointer events} only within a non-rectangular region, - as illustrated in the \l {Qt Quick Examples - Shapes}{Shapes example} - (see \c tapableTriangle.qml). + A \l Shape can be used as a mask, to make an item react to + \l {QPointerEvent}{pointer events} only within a non-rectangular region: + + \table + \row + \li \image containmentMask-shape.gif + \li \snippet qml/item/containmentMask-shape.qml 0 + \endtable + + It is also possible to define the contains method in QML. For example, + to create a circular item that only responds to events within its + actual bounds: + + \table + \row + \li \image containmentMask-circle.gif + \li \snippet qml/item/containmentMask-circle-js.qml 0 + \endtable + + \sa {Qt Quick Examples - Shapes} */ /*! \property QQuickItem::containmentMask -- cgit v1.2.3 From 0d44864b29efea8a0cc3c634b32362f4b44254f7 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 21 May 2021 13:42:35 +0200 Subject: Support ' in styled text Change-Id: I4a8db963e52a7899ab1796f9a560e8029cc1c929 Reviewed-by: Fabian Kosmale Reviewed-by: Eskil Abrahamsen Blomfeldt (cherry picked from commit 96b528efcba1226d2980828d1255160bdceae4cf) Reviewed-by: Shawn Rutledge --- src/quick/items/qquicktext.cpp | 2 +- src/quick/util/qquickstyledtext.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index b6c81f266c..b348ce74a8 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -2168,7 +2168,7 @@ void QQuickText::resetMaximumLineCount() - inline images
    ,
      and
    • - ordered and unordered lists
       - preformatted
      -    > < &
      +    > < & "   '
           \endcode
       
           \c Text.StyledText parser is strict, requiring tags to be correctly nested.
      diff --git a/src/quick/util/qquickstyledtext.cpp b/src/quick/util/qquickstyledtext.cpp
      index f209a14f35..4c42e20686 100644
      --- a/src/quick/util/qquickstyledtext.cpp
      +++ b/src/quick/util/qquickstyledtext.cpp
      @@ -564,6 +564,8 @@ void QQuickStyledTextPrivate::parseEntity(const QChar *&ch, const QString &textI
                       textOut += QChar(60);
                   else if (entity == QLatin1String("amp"))
                       textOut += QChar(38);
      +            else if (entity == QLatin1String("apos"))
      +                textOut += QChar(39);
                   else if (entity == QLatin1String("quot"))
                       textOut += QChar(34);
                   else if (entity == QLatin1String("nbsp"))
      -- 
      cgit v1.2.3
      
      
      From 0008a6a9d24e56e085c32acd1b514d78460757d0 Mon Sep 17 00:00:00 2001
      From: Richard Moe Gustavsen 
      Date: Mon, 14 Feb 2022 11:29:26 +0100
      Subject: QQuickWindow: improve docs for activeFocusItem
      
      Change-Id: I6e107095a7dbd074e076ac6762f18cecf484691f
      Reviewed-by: Venugopal Shivashankar 
      (cherry picked from commit 22e4f38858db25b939c4efdc6dae1f2fe6b52774)
      Reviewed-by: Qt Cherry-pick Bot 
      ---
       src/quick/items/qquickwindow.cpp | 2 ++
       1 file changed, 2 insertions(+)
      
      diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
      index fd9392c502..fd2b868c3b 100644
      --- a/src/quick/items/qquickwindow.cpp
      +++ b/src/quick/items/qquickwindow.cpp
      @@ -1708,6 +1708,8 @@ QQuickItem *QQuickWindow::contentItem() const
       
           \brief The item which currently has active focus or \c null if there is
           no item with active focus.
      +
      +    \sa QQuickItem::forceActiveFocus(), {Keyboard Focus in Qt Quick}
       */
       QQuickItem *QQuickWindow::activeFocusItem() const
       {
      -- 
      cgit v1.2.3
      
      
      From c4f02e37124502828be7b754ad327d8b22abacd4 Mon Sep 17 00:00:00 2001
      From: Ivan Solovev 
      Date: Mon, 21 Feb 2022 16:02:58 +0100
      Subject: A11Y: make QQuickText focusable for A11Y
      
      A QtQuick Text element is used to represent a separate block of text
      in a window.
      Normally, when TalkBack is enabled, the user expects to be able to
      navigate between separate blocks of text with regular A11Y gestures.
      However before this patch the Text elements were not focusable by
      default, so all the Text elements in the Window were read by the
      TalkBack successively, as if it was one element.
      This could be solved by explicitly adding
      
       Accessible.focusable: true
      
      to the properties of every Text element.
      
      This patch enables A11Y focus on Text elements by default.
      
      Fixes: QTBUG-77371
      Change-Id: Icfcef6ee301b9218bb9ace97a05432c9fc2ffb0a
      Reviewed-by: Assam Boudjelthia 
      (cherry picked from commit 9c5f772b5eb008cd0d00a0801b80a399fdc0e3c9)
      ---
       src/quick/accessible/qaccessiblequickitem.cpp              | 7 ++++++-
       src/quick/items/qquickaccessibleattached.cpp               | 5 +++--
       tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp | 1 +
       3 files changed, 10 insertions(+), 3 deletions(-)
      
      diff --git a/src/quick/accessible/qaccessiblequickitem.cpp b/src/quick/accessible/qaccessiblequickitem.cpp
      index d37b276496..3d89d33769 100644
      --- a/src/quick/accessible/qaccessiblequickitem.cpp
      +++ b/src/quick/accessible/qaccessiblequickitem.cpp
      @@ -177,6 +177,11 @@ QList QAccessibleQuickItem::childItems() const
           return accessibleUnignoredChildren(item());
       }
       
      +static bool isTextRole(QAccessible::Role role)
      +{
      +    return role == QAccessible::EditableText || role == QAccessible::StaticText;
      +}
      +
       QAccessible::State QAccessibleQuickItem::state() const
       {
           QQuickAccessibleAttached *attached = QQuickAccessibleAttached::attachedProperties(item());
      @@ -194,7 +199,7 @@ QAccessible::State QAccessibleQuickItem::state() const
               state.offscreen = true;
           if ((role() == QAccessible::CheckBox || role() == QAccessible::RadioButton) && object()->property("checked").toBool())
               state.checked = true;
      -    if (item()->activeFocusOnTab() || role() == QAccessible::EditableText)
      +    if (item()->activeFocusOnTab() || isTextRole(role()))
               state.focusable = true;
           if (item()->hasActiveFocus())
               state.focused = true;
      diff --git a/src/quick/items/qquickaccessibleattached.cpp b/src/quick/items/qquickaccessibleattached.cpp
      index fbdb17c7b9..38c2310c2b 100644
      --- a/src/quick/items/qquickaccessibleattached.cpp
      +++ b/src/quick/items/qquickaccessibleattached.cpp
      @@ -406,9 +406,10 @@ void QQuickAccessibleAttached::setRole(QAccessible::Role role)
                       m_state.focusable = true;
                   break;
               case QAccessible::StaticText:
      -            if (!m_stateExplicitlySet.readOnly) {
      +            if (!m_stateExplicitlySet.readOnly)
                       m_state.readOnly = true;
      -            }
      +            if (!m_stateExplicitlySet.focusable)
      +                m_state.focusable = true;
                   break;
               default:
                   break;
      diff --git a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
      index 0e6c3b3ad9..30d57b9c9a 100644
      --- a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
      +++ b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
      @@ -383,6 +383,7 @@ void tst_QQuickAccessible::basicPropertiesTest()
           QCOMPARE(item->indexOfChild(text2), 1);
           QCOMPARE(text2->state().editable, 0u);
           QCOMPARE(text2->state().readOnly, 1);
      +    QCOMPARE(text2->state().focusable, 1);
       
           QCOMPARE(iface->indexOfChild(text2), -1);
           QCOMPARE(text2->indexOfChild(item), -1);
      -- 
      cgit v1.2.3
      
      
      From 0a763d49504d8bebaa6f097f8e2ae558a62bca89 Mon Sep 17 00:00:00 2001
      From: Eskil Abrahamsen Blomfeldt 
      Date: Thu, 3 Mar 2022 15:12:31 +0100
      Subject: Fix crash with NativeRendering on RHI
      
      Amends 4757cac470edbeaeaceca4e63075d9f1139f546b with the compiled
      versions of the modified shaders. Missing these will actually cause
      an assert when using NativeRendering together with QSG_RHI=1.
      
      Change-Id: I1ef5235659ab3da3044d04630f1377808847ec51
      Reviewed-by: Laszlo Agocs 
      ---
       .../scenegraph/shaders_ng/24bittextmask.frag.qsb      | Bin 1469 -> 1579 bytes
       .../scenegraph/shaders_ng/32bitcolortext.frag.qsb     | Bin 1344 -> 1436 bytes
       src/quick/scenegraph/shaders_ng/8bittextmask.frag.qsb | Bin 1351 -> 1433 bytes
       .../scenegraph/shaders_ng/8bittextmask_a.frag.qsb     | Bin 845 -> 926 bytes
       src/quick/scenegraph/shaders_ng/outlinedtext.frag.qsb | Bin 2174 -> 2266 bytes
       src/quick/scenegraph/shaders_ng/outlinedtext.vert.qsb | Bin 2623 -> 2743 bytes
       .../scenegraph/shaders_ng/outlinedtext_a.frag.qsb     | Bin 1437 -> 1528 bytes
       src/quick/scenegraph/shaders_ng/styledtext.frag.qsb   | Bin 1740 -> 1834 bytes
       src/quick/scenegraph/shaders_ng/styledtext.vert.qsb   | Bin 2175 -> 2294 bytes
       src/quick/scenegraph/shaders_ng/styledtext_a.frag.qsb | Bin 1158 -> 1236 bytes
       src/quick/scenegraph/shaders_ng/textmask.frag.qsb     | Bin 1469 -> 1561 bytes
       src/quick/scenegraph/shaders_ng/textmask.vert.qsb     | Bin 1933 -> 2047 bytes
       12 files changed, 0 insertions(+), 0 deletions(-)
      
      diff --git a/src/quick/scenegraph/shaders_ng/24bittextmask.frag.qsb b/src/quick/scenegraph/shaders_ng/24bittextmask.frag.qsb
      index c493996375..6eee3f01d6 100644
      Binary files a/src/quick/scenegraph/shaders_ng/24bittextmask.frag.qsb and b/src/quick/scenegraph/shaders_ng/24bittextmask.frag.qsb differ
      diff --git a/src/quick/scenegraph/shaders_ng/32bitcolortext.frag.qsb b/src/quick/scenegraph/shaders_ng/32bitcolortext.frag.qsb
      index 3f8489bfe6..d81bb2f26d 100644
      Binary files a/src/quick/scenegraph/shaders_ng/32bitcolortext.frag.qsb and b/src/quick/scenegraph/shaders_ng/32bitcolortext.frag.qsb differ
      diff --git a/src/quick/scenegraph/shaders_ng/8bittextmask.frag.qsb b/src/quick/scenegraph/shaders_ng/8bittextmask.frag.qsb
      index f721207325..6ebb3342ac 100644
      Binary files a/src/quick/scenegraph/shaders_ng/8bittextmask.frag.qsb and b/src/quick/scenegraph/shaders_ng/8bittextmask.frag.qsb differ
      diff --git a/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag.qsb b/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag.qsb
      index 93ac0124be..e29f734c33 100644
      Binary files a/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag.qsb and b/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag.qsb differ
      diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext.frag.qsb b/src/quick/scenegraph/shaders_ng/outlinedtext.frag.qsb
      index 1756ee9d4b..071abd2f88 100644
      Binary files a/src/quick/scenegraph/shaders_ng/outlinedtext.frag.qsb and b/src/quick/scenegraph/shaders_ng/outlinedtext.frag.qsb differ
      diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext.vert.qsb b/src/quick/scenegraph/shaders_ng/outlinedtext.vert.qsb
      index b8d38bdff4..dd159d008d 100644
      Binary files a/src/quick/scenegraph/shaders_ng/outlinedtext.vert.qsb and b/src/quick/scenegraph/shaders_ng/outlinedtext.vert.qsb differ
      diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag.qsb b/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag.qsb
      index f44b92dc28..393b1608e9 100644
      Binary files a/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag.qsb and b/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag.qsb differ
      diff --git a/src/quick/scenegraph/shaders_ng/styledtext.frag.qsb b/src/quick/scenegraph/shaders_ng/styledtext.frag.qsb
      index b0461a686c..5b45142201 100644
      Binary files a/src/quick/scenegraph/shaders_ng/styledtext.frag.qsb and b/src/quick/scenegraph/shaders_ng/styledtext.frag.qsb differ
      diff --git a/src/quick/scenegraph/shaders_ng/styledtext.vert.qsb b/src/quick/scenegraph/shaders_ng/styledtext.vert.qsb
      index 18e4685d21..e2a5859bfc 100644
      Binary files a/src/quick/scenegraph/shaders_ng/styledtext.vert.qsb and b/src/quick/scenegraph/shaders_ng/styledtext.vert.qsb differ
      diff --git a/src/quick/scenegraph/shaders_ng/styledtext_a.frag.qsb b/src/quick/scenegraph/shaders_ng/styledtext_a.frag.qsb
      index 3d9b5a0bdd..c3aa6c068a 100644
      Binary files a/src/quick/scenegraph/shaders_ng/styledtext_a.frag.qsb and b/src/quick/scenegraph/shaders_ng/styledtext_a.frag.qsb differ
      diff --git a/src/quick/scenegraph/shaders_ng/textmask.frag.qsb b/src/quick/scenegraph/shaders_ng/textmask.frag.qsb
      index cfae9575da..a4341d8915 100644
      Binary files a/src/quick/scenegraph/shaders_ng/textmask.frag.qsb and b/src/quick/scenegraph/shaders_ng/textmask.frag.qsb differ
      diff --git a/src/quick/scenegraph/shaders_ng/textmask.vert.qsb b/src/quick/scenegraph/shaders_ng/textmask.vert.qsb
      index 2ea425e1c0..4ca3b874d0 100644
      Binary files a/src/quick/scenegraph/shaders_ng/textmask.vert.qsb and b/src/quick/scenegraph/shaders_ng/textmask.vert.qsb differ
      -- 
      cgit v1.2.3
      
      
      From 61d3d80261a10c134aedda2fe26431fdab06607a Mon Sep 17 00:00:00 2001
      From: Tony Leinonen 
      Date: Thu, 21 Oct 2021 14:44:02 +0300
      Subject: Reset currentChanges if currentChanges is active when refilling
       listView
      
      currentIndex was not getting updated because itemViewChangeSet was left
      active from previous interaction. Clear the changes if they are still
      active on refill.
      
      Task-number: QTBUG-92809
      Change-Id: I81558a5e0bfe0f880851fff85370bd5be60a5391
      Reviewed-by: Richard Moe Gustavsen 
      (cherry picked from commit 2d8033a4ffb9ca60adee29d375491d7ed2a82747)
      Reviewed-by: Qt CI Bot 
      Reviewed-by: Tony Leinonen 
      ---
       src/quick/items/qquickitemview.cpp                 |   2 +-
       .../auto/quick/qquicklistview/data/qtbug_92809.qml | 119 +++++++++++++++++++++
       .../quick/qquicklistview/tst_qquicklistview.cpp    |  26 +++++
       3 files changed, 146 insertions(+), 1 deletion(-)
       create mode 100644 tests/auto/quick/qquicklistview/data/qtbug_92809.qml
      
      diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
      index 3999109e47..fda2e6ff79 100644
      --- a/src/quick/items/qquickitemview.cpp
      +++ b/src/quick/items/qquickitemview.cpp
      @@ -1785,7 +1785,7 @@ void QQuickItemViewPrivate::refill(qreal from, qreal to)
       
           do {
               bufferPause.stop();
      -        if (currentChanges.hasPendingChanges() || bufferedChanges.hasPendingChanges()) {
      +        if (currentChanges.hasPendingChanges() || bufferedChanges.hasPendingChanges() || currentChanges.active) {
                   currentChanges.reset();
                   bufferedChanges.reset();
                   releaseVisibleItems(reusableFlag);
      diff --git a/tests/auto/quick/qquicklistview/data/qtbug_92809.qml b/tests/auto/quick/qquicklistview/data/qtbug_92809.qml
      new file mode 100644
      index 0000000000..c0b7ac546b
      --- /dev/null
      +++ b/tests/auto/quick/qquicklistview/data/qtbug_92809.qml
      @@ -0,0 +1,119 @@
      +/****************************************************************************
      +**
      +** 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
      +import QtQml.Models 2.12
      +
      +Rectangle {
      +    id: root
      +    width: 800
      +    height: 480
      +
      +    property list myModel: [
      +        QtObject { property string name: "Item 0"; property bool selected: true },
      +        QtObject { property string name: "Item 1"; property bool selected: true },
      +        QtObject { property string name: "Item 2"; property bool selected: true },
      +        QtObject { property string name: "Item 3"; property bool selected: true },
      +        QtObject { property string name: "Item 4"; property bool selected: true },
      +        QtObject { property string name: "Item 5"; property bool selected: true },
      +        QtObject { property string name: "Item 6"; property bool selected: true },
      +        QtObject { property string name: "Item 7"; property bool selected: true },
      +        QtObject { property string name: "Item 8"; property bool selected: true },
      +        QtObject { property string name: "Item 9"; property bool selected: true },
      +        QtObject { property string name: "Press Enter here"; property bool selected: true }
      +    ]
      +
      +    DelegateModel {
      +        objectName: "model"
      +        id: visualModel
      +        model: myModel
      +        filterOnGroup: "selected"
      +
      +        groups: [
      +            DelegateModelGroup {
      +                name: "selected"
      +                includeByDefault: true
      +            }
      +        ]
      +
      +        delegate: Rectangle {
      +            width: 180
      +            height: 180
      +            visible: DelegateModel.inSelected
      +            color: ListView.isCurrentItem ? "orange" : "yellow"
      +            Component.onCompleted: {
      +                DelegateModel.inPersistedItems = true
      +                DelegateModel.inSelected = Qt.binding(function() { return model.selected })
      +            }
      +        }
      +    }
      +
      +    ListView {
      +        objectName: "list"
      +        anchors.fill: parent
      +        spacing: 180/15
      +        orientation: ListView.Horizontal
      +        model: visualModel
      +        focus: true
      +        currentIndex: 0
      +        preferredHighlightBegin: (width-180)/2
      +        preferredHighlightEnd: (width+180)/2
      +        highlightRangeMode: ListView.StrictlyEnforceRange
      +        highlightMoveDuration: 300
      +        highlightMoveVelocity: -1
      +        cacheBuffer: 0
      +
      +        onCurrentIndexChanged: {
      +            if (currentIndex === 10) {
      +                myModel[6].selected = !myModel[6].selected
      +            }
      +        }
      +    }
      +}
      diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
      index 7b17c014d5..57d7dddf20 100644
      --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
      +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
      @@ -306,6 +306,7 @@ private slots:
       
       
           void singletonModelLifetime();
      +    void QTBUG_92809();
       
       private:
           template  void items(const QUrl &source);
      @@ -10224,6 +10225,31 @@ void tst_QQuickListView::singletonModelLifetime()
           QTRY_VERIFY(engine.rootObjects().first()->property("alive").toBool());
       }
       
      +void tst_QQuickListView::QTBUG_92809()
      +{
      +    QScopedPointer window(createView());
      +    QTRY_VERIFY(window);
      +    window->setSource(testFileUrl("qtbug_92809.qml"));
      +    window->show();
      +    QVERIFY(QTest::qWaitForWindowExposed(window.data()));
      +
      +    QQuickListView *listview = findItem(window->rootObject(), "list");
      +    QTRY_VERIFY(listview != nullptr);
      +    QVERIFY(QQuickTest::qWaitForItemPolished(listview));
      +    listview->setCurrentIndex(1);
      +    QVERIFY(QQuickTest::qWaitForItemPolished(listview));
      +    listview->setCurrentIndex(2);
      +    QVERIFY(QQuickTest::qWaitForItemPolished(listview));
      +    listview->setCurrentIndex(3);
      +    QVERIFY(QQuickTest::qWaitForItemPolished(listview));
      +    QTest::qWait(500);
      +    listview->setCurrentIndex(10);
      +    QVERIFY(QQuickTest::qWaitForItemPolished(listview));
      +    QTest::qWait(500);
      +    int currentIndex = listview->currentIndex();
      +    QTRY_COMPARE(currentIndex, 9);
      +}
      +
       QTEST_MAIN(tst_QQuickListView)
       
       #include "tst_qquicklistview.moc"
      -- 
      cgit v1.2.3
      
      
      From f063ad95638f3b396d59950e1ec17170181c98c3 Mon Sep 17 00:00:00 2001
      From: CI Insignificant Platforms Monitor Bot
       
      Date: Mon, 7 Mar 2022 12:25:26 +0000
      Subject: Blacklist: test cases blacklisted in tst_QQuickMultiPointTouchArea:
      
       - nonOverlapping on ubuntu-20
       - nested on ubuntu-20
      
      Task-number: QTBUG-101499
      Change-Id: Ieb394294dd4c99cc9a6d069eda303bdd24a53547
      Reviewed-by: CI Insignificant Platforms Monitor Bot 
      ---
       tests/auto/quick/qquickmultipointtoucharea/BLACKLIST | 4 ++++
       1 file changed, 4 insertions(+)
      
      diff --git a/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST b/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST
      index 6af00ab76f..cfbd47d3dc 100644
      --- a/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST
      +++ b/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST
      @@ -1,10 +1,14 @@
       [nonOverlapping]
      +# QTBUG-101499
      +ubuntu-20
       ubuntu-16.04
       ubuntu-18.04
       opensuse-42.3
       opensuse-leap
       sles
       [nested]
      +# QTBUG-101499
      +ubuntu-20
       ubuntu-16.04
       ubuntu-18.04
       opensuse-42.3
      -- 
      cgit v1.2.3
      
      
      From 4012a53aca14adad341d1fe3220eea085fe508d7 Mon Sep 17 00:00:00 2001
      From: CI Insignificant Platforms Monitor Bot
       
      Date: Mon, 7 Mar 2022 12:25:21 +0000
      Subject: Blacklist: test cases blacklisted in tst_QQuickListView:
      
       - currentIndex on ubuntu-20
      
      Task-number: QTBUG-101498
      Change-Id: Ic67299d3f6362ea3ce26aeb9ef19ea220e745a56
      Reviewed-by: CI Insignificant Platforms Monitor Bot 
      ---
       tests/auto/quick/qquicklistview/BLACKLIST | 2 ++
       1 file changed, 2 insertions(+)
      
      diff --git a/tests/auto/quick/qquicklistview/BLACKLIST b/tests/auto/quick/qquicklistview/BLACKLIST
      index 6ef69550a4..cba2e8d752 100644
      --- a/tests/auto/quick/qquicklistview/BLACKLIST
      +++ b/tests/auto/quick/qquicklistview/BLACKLIST
      @@ -9,6 +9,8 @@ macos
       #QTBUG-75960
       #QTBUG-76652
       [currentIndex]
      +# QTBUG-101498
      +ubuntu-20
       macos
       opensuse-leap
       ubuntu-18.04
      -- 
      cgit v1.2.3
      
      
      From 36ce76f787b57fd2096e7368c82df73ff09c05f8 Mon Sep 17 00:00:00 2001
      From: Vlad Zahorodnii 
      Date: Sun, 10 Oct 2021 21:04:21 +0300
      Subject: Fix sweep step for tainted QObject JavaScript wrappers
      
      Currently, whenever the garbage collector runs, it will destroy all
      valid tainted wrappers.
      
      Only null or undefined wrappers will be preserved in the
      m_multiplyWrappedQObjects map.
      
      It seems like "!" was overlooked in
      3b5d37ce3841c4bfdf1c629d33f0e33b881b47fb. Prior to that change, it
      was "!it.value()->markBit()", so calling erase() in the then branch
      did make sense. But with "!it.value().isNullOrUndefined()", erase()
      will be called for every valid wrapper, which is the opposite what we
      want.
      
      Change-Id: I2bf2630f538af8cbd4bfffcff29d67be6c278265
      Reviewed-by: Fabian Kosmale 
      (cherry picked from commit e6b2f88d892dcf396580a61662f569bf69d6d9d1)
      Reviewed-by: Qt Cherry-pick Bot 
      ---
       src/qml/memory/qv4mm.cpp                   |  2 +-
       tests/auto/qml/qjsengine/tst_qjsengine.cpp | 39 ++++++++++++++++++++++++++++++
       tests/auto/qml/qv4mm/tst_qv4mm.cpp         |  6 ++---
       3 files changed, 43 insertions(+), 4 deletions(-)
      
      diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
      index 309df6d180..216a82718b 100644
      --- a/src/qml/memory/qv4mm.cpp
      +++ b/src/qml/memory/qv4mm.cpp
      @@ -981,7 +981,7 @@ void MemoryManager::sweep(bool lastSweep, ClassDestroyStatsCallback classCountPt
       
           if (MultiplyWrappedQObjectMap *multiplyWrappedQObjects = engine->m_multiplyWrappedQObjects) {
               for (MultiplyWrappedQObjectMap::Iterator it = multiplyWrappedQObjects->begin(); it != multiplyWrappedQObjects->end();) {
      -            if (!it.value().isNullOrUndefined())
      +            if (it.value().isNullOrUndefined())
                       it = multiplyWrappedQObjects->erase(it);
                   else
                       ++it;
      diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
      index 3b7d74df63..b75bf820d5 100644
      --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
      +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
      @@ -102,6 +102,7 @@ private slots:
           void valueConversion_RegularExpression();
           void castWithMultipleInheritance();
           void collectGarbage();
      +    void collectGarbageNestedWrappersTwoEngines();
           void gcWithNestedDataStructure();
           void stacktrace();
           void numberParsing_data();
      @@ -1809,6 +1810,44 @@ void tst_QJSEngine::collectGarbage()
           QVERIFY(ptr.isNull());
       }
       
      +class TestObjectContainer : public QObject
      +{
      +    Q_OBJECT
      +    Q_PROPERTY(QObject *dummy MEMBER m_dummy CONSTANT)
      +
      +public:
      +    TestObjectContainer() : m_dummy(new QObject(this)) {}
      +
      +private:
      +    QObject *m_dummy;
      +};
      +
      +void tst_QJSEngine::collectGarbageNestedWrappersTwoEngines()
      +{
      +    QJSEngine engine1;
      +    QJSEngine engine2;
      +
      +    TestObjectContainer container;
      +    QQmlEngine::setObjectOwnership(&container, QQmlEngine::CppOwnership);
      +
      +    engine1.globalObject().setProperty("foobar", engine1.newQObject(&container));
      +    engine2.globalObject().setProperty("foobar", engine2.newQObject(&container));
      +
      +    engine1.evaluate("foobar.dummy.baz = 42");
      +    engine2.evaluate("foobar.dummy.baz = 43");
      +
      +    QCOMPARE(engine1.evaluate("foobar.dummy.baz").toInt(), 42);
      +    QCOMPARE(engine2.evaluate("foobar.dummy.baz").toInt(), 43);
      +
      +    engine1.collectGarbage();
      +    engine2.collectGarbage();
      +
      +    // The GC should not collect dummy object wrappers neither in engine1 nor engine2, we
      +    // verify that by checking whether the baz property still has its previous value.
      +    QCOMPARE(engine1.evaluate("foobar.dummy.baz").toInt(), 42);
      +    QCOMPARE(engine2.evaluate("foobar.dummy.baz").toInt(), 43);
      +}
      +
       void tst_QJSEngine::gcWithNestedDataStructure()
       {
           // The GC must be able to traverse deeply nested objects, otherwise this
      diff --git a/tests/auto/qml/qv4mm/tst_qv4mm.cpp b/tests/auto/qml/qv4mm/tst_qv4mm.cpp
      index 5d635aa63b..824fd89e5b 100644
      --- a/tests/auto/qml/qv4mm/tst_qv4mm.cpp
      +++ b/tests/auto/qml/qv4mm/tst_qv4mm.cpp
      @@ -76,10 +76,10 @@ void tst_qv4mm::multiWrappedQObjects()
               QCOMPARE(engine1.memoryManager->m_pendingFreedObjectWrapperValue.size(), 1);
               QCOMPARE(engine2.memoryManager->m_pendingFreedObjectWrapperValue.size(), 0);
       
      -        // Moves the additional WeakValue from m_multiplyWrappedQObjects to
      -        // m_pendingFreedObjectWrapperValue. It's still alive after all.
      +        // The additional WeakValue from m_multiplyWrappedQObjects hasn't been moved
      +        // to m_pendingFreedObjectWrapperValue yet. It's still alive after all.
               engine1.memoryManager->runGC();
      -        QCOMPARE(engine1.memoryManager->m_pendingFreedObjectWrapperValue.size(), 2);
      +        QCOMPARE(engine1.memoryManager->m_pendingFreedObjectWrapperValue.size(), 1);
       
               // engine2 doesn't own the object as engine1 was the first to wrap it above.
               // Therefore, no effect here.
      -- 
      cgit v1.2.3
      
      
      From fc1ec5cf4a34b210313eaa26bb0e0229007e58d6 Mon Sep 17 00:00:00 2001
      From: Shawn Rutledge 
      Date: Mon, 29 Jun 2020 15:57:23 +0200
      Subject: Update the window cursor on mouse release
      
      When a PointerHandler with a custom cursor deactivates, the cursor
      wasn't restored until the next mouse move.
      
      I was writing a test to ensure that there were no bugs analogous
      to QTBUG-85303 with a handler that uses its active state to change
      the cursor (unlike HoverHandler which changes it whenever the
      mouse is hovering) and found this new bug.
      
      Fixes: QTBUG-85325
      Task-number: QTBUG-85303
      Change-Id: I4ea8dbd267046c8e972e723cc491bd44bbbfd7f2
      Reviewed-by: Volker Hilsheimer 
      (cherry picked from commit 8bd6342639721b7db08acf554c6bcd3e7ab04cb6)
      Reviewed-by: Shawn Rutledge 
      ---
       src/quick/items/qquickwindow.cpp                             |  3 +++
       .../pointerhandlers/qquickdraghandler/data/dragMargin.qml    |  3 ++-
       .../qquickdraghandler/tst_qquickdraghandler.cpp              | 12 ++++++++++++
       3 files changed, 17 insertions(+), 1 deletion(-)
      
      diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
      index fd2b868c3b..18bf8212d1 100644
      --- a/src/quick/items/qquickwindow.cpp
      +++ b/src/quick/items/qquickwindow.cpp
      @@ -2443,6 +2443,9 @@ void QQuickWindowPrivate::handleMouseEvent(QMouseEvent *event)
               Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseRelease, event->button(),
                                     event->buttons());
               deliverPointerEvent(pointerEventInstance(event));
      +#if QT_CONFIG(cursor)
      +        updateCursor(event->windowPos());
      +#endif
               break;
           case QEvent::MouseButtonDblClick:
               Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseDoubleClick,
      diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragMargin.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragMargin.qml
      index e5ca681bd5..60ea740105 100644
      --- a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragMargin.qml
      +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragMargin.qml
      @@ -1,4 +1,4 @@
      -import QtQuick 2.12
      +import QtQuick 2.15
       
       Rectangle {
           color: "#333"
      @@ -13,6 +13,7 @@ Rectangle {
               DragHandler {
                   id: dragHandler
                   margin: 20
      +            cursorShape: Qt.ClosedHandCursor
               }
       
               Rectangle {
      diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp
      index f71febbaf9..40b138bc70 100644
      --- a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp
      +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp
      @@ -411,6 +411,9 @@ void tst_DragHandler::dragFromMargin() // QTBUG-74966
           QVERIFY(!dragHandler->active());
           QCOMPARE(dragHandler->centroid().scenePosition(), scenePressPos);
           QCOMPARE(dragHandler->centroid().scenePressPosition(), scenePressPos);
      +#if QT_CONFIG(cursor)
      +    QCOMPARE(window->cursor().shape(), Qt::ArrowCursor);
      +#endif
           p1 += QPoint(dragThreshold * 2, 0);
           QTest::mouseMove(window, p1);
           QTRY_VERIFY(dragHandler->active());
      @@ -419,9 +422,18 @@ void tst_DragHandler::dragFromMargin() // QTBUG-74966
           QCOMPARE(dragHandler->translation().x(), 0.0); // hmm that's odd
           QCOMPARE(dragHandler->translation().y(), 0.0);
           QCOMPARE(draggableItem->position(), originalPos + QPointF(dragThreshold * 2, 0));
      +#if QT_CONFIG(cursor)
      +    // The cursor doesn't change until the next event after the handler becomes active.
      +    p1 += QPoint(1, 0);
      +    QTest::mouseMove(window, p1);
      +    QTRY_COMPARE(window->cursor().shape(), Qt::ClosedHandCursor);
      +#endif
           QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
           QTRY_VERIFY(!dragHandler->active());
           QCOMPARE(dragHandler->centroid().pressedButtons(), Qt::NoButton);
      +#if QT_CONFIG(cursor)
      +    QTRY_COMPARE(window->cursor().shape(), Qt::ArrowCursor);
      +#endif
       }
       
       void tst_DragHandler::snapMode_data()
      -- 
      cgit v1.2.3
      
      
      From ed41fb59cad2fabc9b9382c703d16cec8f904acd Mon Sep 17 00:00:00 2001
      From: Marc Mutz 
      Date: Tue, 16 Jul 2019 11:23:37 +0200
      Subject: QSGOpenGLDistanceFieldGlyphCache: fix multiplication result
       truncation
      
      The type of the expression int * int is int, so truncation has already
      happened when the result is assigned to a qint64.
      
      Fix by casting one of the multiplicants to qint64 before performing
      the multiplication. This multiplication cannot overflow, because int
      is 32-bit on all supported platforms.
      
      The addition of 'size' to the pointer will still truncate the result,
      on 32bit platforms, but that check is in itself UB. A follow-up commit
      will fix the check, and with it the last truncation to 32bit.
      
      Coverity-Id: 218769
      Change-Id: I0d71950695b9743db8c96d825e68bb1e9c47de02
      Reviewed-by: Fabian Kosmale 
      Reviewed-by: Thiago Macieira 
      (cherry picked from commit cacfc1dbb9719c0ef55cff69dad0921ce1405438)
      Reviewed-by: Qt Cherry-pick Bot 
      ---
       src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp | 2 +-
       1 file changed, 1 insertion(+), 1 deletion(-)
      
      diff --git a/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp
      index 63319389fe..23e6de51a9 100644
      --- a/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp
      +++ b/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp
      @@ -512,7 +512,7 @@ bool QSGRhiDistanceFieldGlyphCache::loadPregeneratedCache(const QRawFont &font)
       
                   int width = texInfo->allocatedArea.width();
                   int height = texInfo->allocatedArea.height();
      -            qint64 size = width * height;
      +            qint64 size = qint64(width) * height;
                   if (reinterpret_cast(textureData + size) > qtdfTableEnd) {
                       qWarning("qtdf table too small in font '%s'.",
                                qPrintable(font.familyName()));
      -- 
      cgit v1.2.3
      
      
      From a5635345175e667601c8b6a344508c4d4ebb0f9d Mon Sep 17 00:00:00 2001
      From: Marc Mutz 
      Date: Tue, 16 Jul 2019 11:31:01 +0200
      Subject: QSGOpenGLDistanceFieldGlyphCache: fix UB (ordering of pointers not
       from the same array)
      
      The code performed out of bounds checks by adding the size of the
      buffer to a pointer and comparing the result to the the
      one-past-the-end pointer of the buffer.
      
      This is UB, for three reasons:
      
      - in one case, a qint64 is added to a pointer, silently truncating the
        result on 32bit platforms
      
      - if the buffer overflow is large, the pointer value may wrap around,
        yielding a result that is numerically less than the end pointer, but
        still out-of-bounds.
      
      - pointer order is only defined within a C array, plus one past the
        end. On failure, pointers outside that range are compared.
      
      Fix by comparing distance(it, end) with the required size for the
      chunk to be written instead.
      
      Change-Id: I356bb8c8a65a93b8b1c1eb7bac381dd64bea719e
      Reviewed-by: Fabian Kosmale 
      Reviewed-by: Thiago Macieira 
      (cherry picked from commit 8d9bd6b381bfc759d575954801b683354ad6a790)
      Reviewed-by: Qt Cherry-pick Bot 
      ---
       src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp | 6 +++---
       1 file changed, 3 insertions(+), 3 deletions(-)
      
      diff --git a/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp
      index 23e6de51a9..c368661505 100644
      --- a/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp
      +++ b/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp
      @@ -446,7 +446,7 @@ bool QSGRhiDistanceFieldGlyphCache::loadPregeneratedCache(const QRawFont &font)
       
               const char *textureRecord = allocatorData;
               for (int i = 0; i < textureCount; ++i, textureRecord += Qtdf::TextureRecordSize) {
      -            if (textureRecord + Qtdf::TextureRecordSize > qtdfTableEnd) {
      +            if (qtdfTableEnd - textureRecord < Qtdf::TextureRecordSize) {
                       qWarning("qtdf table too small in font '%s'.",
                                qPrintable(font.familyName()));
                       return false;
      @@ -462,7 +462,7 @@ bool QSGRhiDistanceFieldGlyphCache::loadPregeneratedCache(const QRawFont &font)
       
               const char *glyphRecord = textureRecord;
               for (quint32 i = 0; i < glyphCount; ++i, glyphRecord += Qtdf::GlyphRecordSize) {
      -            if (glyphRecord + Qtdf::GlyphRecordSize > qtdfTableEnd) {
      +            if (qtdfTableEnd - glyphRecord < Qtdf:: GlyphRecordSize) {
                       qWarning("qtdf table too small in font '%s'.",
                                qPrintable(font.familyName()));
                       return false;
      @@ -513,7 +513,7 @@ bool QSGRhiDistanceFieldGlyphCache::loadPregeneratedCache(const QRawFont &font)
                   int width = texInfo->allocatedArea.width();
                   int height = texInfo->allocatedArea.height();
                   qint64 size = qint64(width) * height;
      -            if (reinterpret_cast(textureData + size) > qtdfTableEnd) {
      +            if (qtdfTableEnd - reinterpret_cast(textureData) < size) {
                       qWarning("qtdf table too small in font '%s'.",
                                qPrintable(font.familyName()));
                       return false;
      -- 
      cgit v1.2.3