From 221b3f614a9c58cd5ac1aa4c36d36fb8a4cd56d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCri=20Valdmann?= Date: Wed, 20 Sep 2017 15:34:24 +0200 Subject: Fix uninitialized member QSGClipNode::m_is_rectangular Task-number: QTBUG-62112 Change-Id: I8943baf6bd5261b91d8960bb227992b56b720554 Reviewed-by: Laszlo Agocs Reviewed-by: Leena Miettinen --- src/quick/scenegraph/coreapi/qsgnode.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/quick/scenegraph/coreapi/qsgnode.cpp b/src/quick/scenegraph/coreapi/qsgnode.cpp index 264b30b897..22d57001fc 100644 --- a/src/quick/scenegraph/coreapi/qsgnode.cpp +++ b/src/quick/scenegraph/coreapi/qsgnode.cpp @@ -1079,6 +1079,7 @@ void QSGGeometryNode::setInheritedOpacity(qreal opacity) QSGClipNode::QSGClipNode() : QSGBasicGeometryNode(ClipNodeType) + , m_is_rectangular(false) { Q_UNUSED(m_reserved); } @@ -1114,6 +1115,8 @@ QSGClipNode::~QSGClipNode() When this hint is set and it is applicable, the clip region will be generated from clipRect() rather than geometry(). + + By default this property is \c false. */ void QSGClipNode::setIsRectangular(bool rectHint) -- cgit v1.2.3 From 163c515783877b8b0ffb8b5c1bab288addee9745 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Fri, 22 Sep 2017 10:18:08 +0200 Subject: Fix use-after-free when clear()ing all elements from a ListModel Same problem as the problem with remove(), so now clear will call into remove to do the correct thing. See also e29ffa179e9920443a23e2fcb3f0694df32e8a68. [ChangeLog][Qt][Qml] Fix possible use-after-free when clearing all items from a ListModel through JavaScript. Change-Id: Ib9389d80798c4333425b4a49930b1670307d06ac Task-number: QTBUG-59256 Reviewed-by: Simon Hausmann --- src/qml/types/qqmllistmodel.cpp | 66 +++++++++++++++------------------------ src/qml/types/qqmllistmodel_p.h | 2 ++ src/qml/types/qqmllistmodel_p_p.h | 1 - 3 files changed, 28 insertions(+), 41 deletions(-) diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp index 35ee30dccf..2b4e906617 100644 --- a/src/qml/types/qqmllistmodel.cpp +++ b/src/qml/types/qqmllistmodel.cpp @@ -341,7 +341,9 @@ ListModel::ListModel(ListLayout *layout, QQmlListModel *modelCache, int uid) : m void ListModel::destroy() { - clear(); + for (const auto &destroyer : remove(0, elements.count())) + destroyer(); + m_uid = -1; m_layout = 0; if (m_modelCache && m_modelCache->m_primary == false) @@ -557,16 +559,6 @@ void ListModel::set(int elementIndex, QV4::Object *object) } } -void ListModel::clear() -{ - int elementCount = elements.count(); - for (int i=0 ; i < elementCount ; ++i) { - elements[i]->destroy(m_layout); - delete elements[i]; - } - elements.clear(); -} - QVector> ListModel::remove(int index, int count) { QVector> toDestroy; @@ -2025,18 +2017,7 @@ int QQmlListModel::count() const */ void QQmlListModel::clear() { - const int cleared = count(); - - emitItemsAboutToBeRemoved(0, cleared); - - if (m_dynamicRoles) { - qDeleteAll(m_modelObjects); - m_modelObjects.clear(); - } else { - m_listModel->clear(); - } - - emitItemsRemoved(0, cleared); + removeElements(0, count()); } /*! @@ -2060,27 +2041,32 @@ void QQmlListModel::remove(QQmlV4Function *args) return; } - emitItemsAboutToBeRemoved(index, removeCount); + removeElements(index, removeCount); + } else { + qmlWarning(this) << tr("remove: incorrect number of arguments"); + } +} - QVector> toDestroy; - if (m_dynamicRoles) { - for (int i=0 ; i < removeCount ; ++i) { - auto modelObject = m_modelObjects[index+i]; - toDestroy.append([modelObject](){ - delete modelObject; - }); - } - m_modelObjects.remove(index, removeCount); - } else { - toDestroy = m_listModel->remove(index, removeCount); - } +void QQmlListModel::removeElements(int index, int removeCount) +{ + emitItemsAboutToBeRemoved(index, removeCount); - emitItemsRemoved(index, removeCount); - for (const auto &destroyer : toDestroy) - destroyer(); + QVector> toDestroy; + if (m_dynamicRoles) { + for (int i=0 ; i < removeCount ; ++i) { + auto modelObject = m_modelObjects[index+i]; + toDestroy.append([modelObject](){ + delete modelObject; + }); + } + m_modelObjects.remove(index, removeCount); } else { - qmlWarning(this) << tr("remove: incorrect number of arguments"); + toDestroy = m_listModel->remove(index, removeCount); } + + emitItemsRemoved(index, removeCount); + for (const auto &destroyer : toDestroy) + destroyer(); } /*! diff --git a/src/qml/types/qqmllistmodel_p.h b/src/qml/types/qqmllistmodel_p.h index b750d30676..1fda703797 100644 --- a/src/qml/types/qqmllistmodel_p.h +++ b/src/qml/types/qqmllistmodel_p.h @@ -165,6 +165,8 @@ private: void emitItemsInserted(int index, int count); void emitItemsAboutToBeMoved(int from, int to, int n); void emitItemsMoved(int from, int to, int n); + + void removeElements(int index, int removeCount); }; // ### FIXME diff --git a/src/qml/types/qqmllistmodel_p_p.h b/src/qml/types/qqmllistmodel_p_p.h index 4928ad3725..10916f10db 100644 --- a/src/qml/types/qqmllistmodel_p_p.h +++ b/src/qml/types/qqmllistmodel_p_p.h @@ -366,7 +366,6 @@ public: int append(QV4::Object *object); void insert(int elementIndex, QV4::Object *object); - void clear(); Q_REQUIRED_RESULT QVector> remove(int index, int count); int appendElement(); -- cgit v1.2.3 From f17b826a72d77379288aa84a933b9231c279cbad Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 22 Sep 2017 15:01:27 +0200 Subject: Fix behaviors not working when sub-types declare properties Since commit 81867dfbf9c16d4300727a08eed9b5c6c979e0ba we have an optimization in place to avoid the virtual meta-call when writing properties that cannot be intercepted. Unfortunately that check did not take parent VME meta-objects into account, which triggered the bug. Test case by Harald Hvaal Task-number: QTBUG-63365 Change-Id: I66cb2967da2c09ca5e38cebd9db2ee6e3ee78f5f Reviewed-by: Erik Verbruggen --- src/qml/qml/qqmlvmemetaobject_p.h | 2 ++ .../quick/qquickbehaviors/data/ItemWithInnerBehavior.qml | 10 ++++++++++ .../quick/qquickbehaviors/data/overwrittenbehavior.qml | 14 ++++++++++++++ tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp | 9 +++++++++ 4 files changed, 35 insertions(+) create mode 100644 tests/auto/quick/qquickbehaviors/data/ItemWithInnerBehavior.qml create mode 100644 tests/auto/quick/qquickbehaviors/data/overwrittenbehavior.qml diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h index ede1dd74f9..2dff2b7a01 100644 --- a/src/qml/qml/qqmlvmemetaobject_p.h +++ b/src/qml/qml/qqmlvmemetaobject_p.h @@ -112,6 +112,8 @@ public: if (it->m_propertyIndex == propertyIndex) return true; } + if (auto parentInterceptor = ((parent.isT1() && parent.flag()) ? static_cast(parent.asT1()) : 0)) + return parentInterceptor->intercepts(propertyIndex); return false; } diff --git a/tests/auto/quick/qquickbehaviors/data/ItemWithInnerBehavior.qml b/tests/auto/quick/qquickbehaviors/data/ItemWithInnerBehavior.qml new file mode 100644 index 0000000000..09983645ef --- /dev/null +++ b/tests/auto/quick/qquickbehaviors/data/ItemWithInnerBehavior.qml @@ -0,0 +1,10 @@ +import QtQuick 2.4 + +Item { + id: root + + property bool someValue + Behavior on someValue { + ScriptAction { script: { parent.behaviorTriggered = true }} + } +} diff --git a/tests/auto/quick/qquickbehaviors/data/overwrittenbehavior.qml b/tests/auto/quick/qquickbehaviors/data/overwrittenbehavior.qml new file mode 100644 index 0000000000..e627c45782 --- /dev/null +++ b/tests/auto/quick/qquickbehaviors/data/overwrittenbehavior.qml @@ -0,0 +1,14 @@ +import QtQuick 2.4 + +Item { + property bool behaviorTriggered + property bool someProperty + + ItemWithInnerBehavior { + //the existence of this property triggers the bug + property bool iDoAbsolutelyNothing + + Component.onCompleted: parent.someProperty = true + someValue: parent.someProperty + } +} diff --git a/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp b/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp index 80c76a377b..bdd53702e5 100644 --- a/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp +++ b/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp @@ -72,6 +72,7 @@ private slots: void currentValue(); void disabledWriteWhileRunning(); void aliasedProperty(); + void innerBehaviorOverwritten(); }; void tst_qquickbehaviors::simpleBehavior() @@ -589,6 +590,14 @@ void tst_qquickbehaviors::aliasedProperty() //i.e. the behavior has been triggered } +void tst_qquickbehaviors::innerBehaviorOverwritten() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("overwrittenbehavior.qml")); + QScopedPointer item(qobject_cast(c.create())); + QVERIFY(item->property("behaviorTriggered").toBool()); +} + QTEST_MAIN(tst_qquickbehaviors) #include "tst_qquickbehaviors.moc" -- cgit v1.2.3 From fa52bb665d6beb77a951c14c8edcba3541850afc Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 25 Sep 2017 16:53:24 +0200 Subject: Fix no-opengl builds The qquickwidgets examples uses OpenGL directly Change-Id: I1cc8cfbcf249abc98473287a9d499032232828c7 Reviewed-by: Simon Hausmann --- examples/quick/quick.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/quick/quick.pro b/examples/quick/quick.pro index 445dfb0fab..7da255e903 100644 --- a/examples/quick/quick.pro +++ b/examples/quick/quick.pro @@ -36,7 +36,7 @@ qtConfig(opengl(es1|es2)?) { # Widget dependent examples qtHaveModule(widgets) { SUBDIRS += embeddedinwidgets - qtHaveModule(quickwidgets): SUBDIRS += quickwidgets + qtHaveModule(quickwidgets):qtConfig(opengl(es1|es2)?): SUBDIRS += quickwidgets } EXAMPLE_FILES = \ -- cgit v1.2.3 From c2f9d8a99db280941237b7ed35052547d55bd014 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 25 Sep 2017 15:22:28 +0200 Subject: ObjectModel: provide unique move IDs QQuickItemViewPrivate::removeItem() uses a QHash to store items that were removed due to a move. If the move IDs are not unique, multiple buffered moves end up overriding each other. This results to leaked items that are never released. Task-number: QTBUG-62607 Change-Id: I7e7e7fcd6b1b0aa50ed55643ba5674e98536f89f Reviewed-by: Mitch Curtis Reviewed-by: Michael Brasser --- src/qml/types/qqmlobjectmodel.cpp | 6 +++--- tests/auto/qml/qqmlobjectmodel/tst_qqmlobjectmodel.cpp | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/qml/types/qqmlobjectmodel.cpp b/src/qml/types/qqmlobjectmodel.cpp index 64d0169f6b..dcd0360199 100644 --- a/src/qml/types/qqmlobjectmodel.cpp +++ b/src/qml/types/qqmlobjectmodel.cpp @@ -72,7 +72,7 @@ public: int ref; }; - QQmlObjectModelPrivate() : QObjectPrivate() {} + QQmlObjectModelPrivate() : QObjectPrivate(), moveId(0) {} static void children_append(QQmlListProperty *prop, QObject *item) { int index = static_cast(prop->data)->children.count(); @@ -129,7 +129,7 @@ public: } QQmlChangeSet changeSet; - changeSet.move(from, to, n, 0); + changeSet.move(from, to, n, ++moveId); emit q->modelUpdated(changeSet, false); emit q->childrenChanged(); } @@ -166,7 +166,7 @@ public: return -1; } - + uint moveId; QList children; }; diff --git a/tests/auto/qml/qqmlobjectmodel/tst_qqmlobjectmodel.cpp b/tests/auto/qml/qqmlobjectmodel/tst_qqmlobjectmodel.cpp index 6ac0412ae5..fb63d811a8 100644 --- a/tests/auto/qml/qqmlobjectmodel/tst_qqmlobjectmodel.cpp +++ b/tests/auto/qml/qqmlobjectmodel/tst_qqmlobjectmodel.cpp @@ -47,18 +47,18 @@ static bool compareItems(QQmlObjectModel *model, const QObjectList &items) return true; } -static bool verifyChangeSet(const QQmlChangeSet &changeSet, int expectedInserts, int expectedRemoves, bool isMove) +static bool verifyChangeSet(const QQmlChangeSet &changeSet, int expectedInserts, int expectedRemoves, bool isMove, int moveId = -1) { int actualRemoves = 0; for (const QQmlChangeSet::Change &r : changeSet.removes()) { - if (r.isMove() != isMove) + if (r.isMove() != isMove && (!isMove || moveId == r.moveId)) return false; actualRemoves += r.count; } int actualInserts = 0; for (const QQmlChangeSet::Change &i : changeSet.inserts()) { - if (i.isMove() != isMove) + if (i.isMove() != isMove && (!isMove || moveId == i.moveId)) return false; actualInserts += i.count; } @@ -129,7 +129,7 @@ void tst_QQmlObjectModel::changes() QCOMPARE(countSpy.count(), countSignals); QCOMPARE(childrenSpy.count(), ++childrenSignals); QCOMPARE(modelUpdateSpy.count(), ++modelUpdateSignals); - QVERIFY(verifyChangeSet(modelUpdateSpy.last().first().value(), 1, 1, true)); + QVERIFY(verifyChangeSet(modelUpdateSpy.last().first().value(), 1, 1, true, 1)); // move(3, 2) -> [item0, item1, item2, item3] model.move(3, 2); items.move(3, 2); @@ -138,7 +138,7 @@ void tst_QQmlObjectModel::changes() QCOMPARE(countSpy.count(), countSignals); QCOMPARE(childrenSpy.count(), ++childrenSignals); QCOMPARE(modelUpdateSpy.count(), ++modelUpdateSignals); - QVERIFY(verifyChangeSet(modelUpdateSpy.last().first().value(), 1, 1, true)); + QVERIFY(verifyChangeSet(modelUpdateSpy.last().first().value(), 1, 1, true, 2)); // remove(0) -> [item1, item2, item3] model.remove(0); items.removeAt(0); -- cgit v1.2.3 From f068f5ddc9cd56dd3dd4fdc2abdbcd1ae8a30f19 Mon Sep 17 00:00:00 2001 From: Zhang Xingtao Date: Mon, 25 Sep 2017 21:18:17 +0800 Subject: Document the default value of property asynchronous Change-Id: I9a01b3f2da0399c84fc7df842f810ae760fd215d Reviewed-by: Miikka Heikkinen Reviewed-by: Shawn Rutledge --- src/quick/items/qquickloader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp index 9f27beb298..cd356a9eeb 100644 --- a/src/quick/items/qquickloader.cpp +++ b/src/quick/items/qquickloader.cpp @@ -852,6 +852,7 @@ qreal QQuickLoader::progress() const \qmlproperty bool QtQuick::Loader::asynchronous This property holds whether the component will be instantiated asynchronously. +By default it is \c false. When used in conjunction with the \l source property, loading and compilation will also be performed in a background thread. -- cgit v1.2.3 From a78b30f408b56f182697a4960a97d4b957e40824 Mon Sep 17 00:00:00 2001 From: Frederik Schwarzer Date: Mon, 6 Feb 2017 13:27:30 +0100 Subject: Docs: remove empty table headers Change-Id: I0693057b57a311b598186a72738021c7d104c41f Reviewed-by: Leena Miettinen --- src/qml/doc/src/cppintegration/data.qdoc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/qml/doc/src/cppintegration/data.qdoc b/src/qml/doc/src/cppintegration/data.qdoc index 723d6e4be1..c4e641331a 100644 --- a/src/qml/doc/src/cppintegration/data.qdoc +++ b/src/qml/doc/src/cppintegration/data.qdoc @@ -174,7 +174,6 @@ function, passing a QVariantList and a QVariantMap, which are automatically converted to JavaScript array and object values, repectively: \table -\header \row \li QML \li \snippet qml/qtbinding/variantlistmap/MyItem.qml 0 @@ -213,7 +212,6 @@ a \c Date object that is automatically converted into a QDateTime value when it is received in C++: \table -\header \row \li QML \li -- cgit v1.2.3 From 265b3bea18c1ac13da413931024f64f49a2da7fc Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 3 Oct 2017 11:30:02 +0200 Subject: Doc: let TextEdit grow vertically in ensureVisible() snippet Binding its height to the height of the flickable means that it's only as tall as the flickable, and hence cannot be interacted with beyond a certain point. The flickable was using the correct height (paintedHeight), which meant that the entire text could be scrolled, just not interacted with. Let it assume its implicitHeight so that it can grow freely. Task-number: QTBUG-48174 Change-Id: I853d0f505466e26e3100e79ff70210fcfa247f0f Reviewed-by: J-P Nurmi Reviewed-by: Shawn Rutledge --- src/quick/doc/snippets/qml/texteditor.qml | 1 - 1 file changed, 1 deletion(-) diff --git a/src/quick/doc/snippets/qml/texteditor.qml b/src/quick/doc/snippets/qml/texteditor.qml index 7da9086e10..9bf13fb27c 100644 --- a/src/quick/doc/snippets/qml/texteditor.qml +++ b/src/quick/doc/snippets/qml/texteditor.qml @@ -63,7 +63,6 @@ Flickable { TextEdit { id: edit width: flick.width - height: flick.height focus: true wrapMode: TextEdit.Wrap onCursorRectangleChanged: flick.ensureVisible(cursorRectangle) -- cgit v1.2.3