aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/imports/layouts/qquicklayout.cpp21
-rw-r--r--src/imports/layouts/qquicklayout_p.h4
-rw-r--r--src/imports/layouts/qquicklinearlayout.cpp10
-rw-r--r--src/imports/layouts/qquicklinearlayout_p.h4
-rw-r--r--tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml31
5 files changed, 65 insertions, 5 deletions
diff --git a/src/imports/layouts/qquicklayout.cpp b/src/imports/layouts/qquicklayout.cpp
index 450cf26cea..17d37b5c4e 100644
--- a/src/imports/layouts/qquicklayout.cpp
+++ b/src/imports/layouts/qquicklayout.cpp
@@ -701,8 +701,10 @@ QQuickItem *QQuickLayoutAttached::item() const
QQuickLayout::QQuickLayout(QQuickLayoutPrivate &dd, QQuickItem *parent)
- : QQuickItem(dd, parent),
- m_dirty(false)
+ : QQuickItem(dd, parent)
+ , m_dirty(false)
+ , m_inUpdatePolish(false)
+ , m_polishInsideUpdatePolish(0)
{
}
@@ -729,7 +731,9 @@ QQuickLayoutAttached *QQuickLayout::qmlAttachedProperties(QObject *object)
void QQuickLayout::updatePolish()
{
+ m_inUpdatePolish = true;
rearrange(QSizeF(width(), height()));
+ m_inUpdatePolish = false;
}
void QQuickLayout::componentComplete()
@@ -750,7 +754,18 @@ void QQuickLayout::invalidate(QQuickItem * /*childItem*/)
if (!qobject_cast<QQuickLayout *>(parentItem())) {
quickLayoutDebug() << "QQuickLayout::invalidate(), polish()";
- polish();
+
+ if (m_inUpdatePolish)
+ ++m_polishInsideUpdatePolish;
+ else
+ m_polishInsideUpdatePolish = 0;
+
+ if (m_polishInsideUpdatePolish <= 2)
+ // allow at most two consecutive loops in order to respond to height-for-width
+ // (e.g QQuickText changes implicitHeight when its width gets changed)
+ polish();
+ else
+ qWarning() << "Qt Quick Layouts: Polish loop detected. Aborting after two iterations.";
}
}
diff --git a/src/imports/layouts/qquicklayout_p.h b/src/imports/layouts/qquicklayout_p.h
index 3f076c7304..d2421667be 100644
--- a/src/imports/layouts/qquicklayout_p.h
+++ b/src/imports/layouts/qquicklayout_p.h
@@ -119,7 +119,9 @@ protected slots:
void invalidateSenderItem();
private:
- bool m_dirty;
+ unsigned m_dirty : 1;
+ unsigned m_inUpdatePolish : 1;
+ unsigned m_polishInsideUpdatePolish : 2;
Q_DECLARE_PRIVATE(QQuickLayout)
diff --git a/src/imports/layouts/qquicklinearlayout.cpp b/src/imports/layouts/qquicklinearlayout.cpp
index c8d2ac5eb2..911793d748 100644
--- a/src/imports/layouts/qquicklinearlayout.cpp
+++ b/src/imports/layouts/qquicklinearlayout.cpp
@@ -469,6 +469,16 @@ void QQuickGridLayoutBase::rearrange(const QSizeF &size)
if (!isReady())
return;
+ const auto refCounter = qScopeGuard([&d] {
+ --(d->m_recurRearrangeCounter);
+ });
+ if (d->m_recurRearrangeCounter++ == 2) {
+ // allow a recursive depth of two in order to respond to height-for-width
+ // (e.g QQuickText changes implicitHeight when its width gets changed)
+ qWarning() << "Qt Quick Layouts: Detected recursive rearrange. Aborting after two iterations.";
+ return;
+ }
+
d->m_rearranging = true;
quickLayoutDebug() << objectName() << "QQuickGridLayoutBase::rearrange()" << size;
Qt::LayoutDirection visualDir = effectiveLayoutDirection();
diff --git a/src/imports/layouts/qquicklinearlayout_p.h b/src/imports/layouts/qquicklinearlayout_p.h
index 6706ebf9fa..866d0884a2 100644
--- a/src/imports/layouts/qquicklinearlayout_p.h
+++ b/src/imports/layouts/qquicklinearlayout_p.h
@@ -104,7 +104,8 @@ class QQuickGridLayoutBasePrivate : public QQuickLayoutPrivate
Q_DECLARE_PUBLIC(QQuickGridLayoutBase)
public:
- QQuickGridLayoutBasePrivate() : m_rearranging(false)
+ QQuickGridLayoutBasePrivate() : m_recurRearrangeCounter(0)
+ , m_rearranging(false)
, m_updateAfterRearrange(false)
, m_layoutDirection(Qt::LeftToRight)
{}
@@ -117,6 +118,7 @@ public:
QQuickGridLayoutEngine engine;
Qt::Orientation orientation;
+ unsigned m_recurRearrangeCounter : 2;
unsigned m_rearranging : 1;
unsigned m_updateAfterRearrange : 1;
QVector<QQuickItem *> m_invalidateAfterRearrange;
diff --git a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
index 07af6a77ac..0732884c97 100644
--- a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
+++ b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
@@ -1100,5 +1100,36 @@ Item {
waitForRendering(rootRect.layout)
compare(rootRect.item1.width, 100)
}
+
+//---------------------------
+ Component {
+ id: rowlayoutWithTextItems_Component
+ RowLayout {
+ Text {
+ Layout.fillWidth: true
+ text: "OneWord"
+ wrapMode: Text.WrapAtWordBoundaryOrAnywhere
+ }
+ Text {
+ Layout.fillWidth: true
+ text: "OneWord"
+ wrapMode: Text.WrapAtWordBoundaryOrAnywhere
+ }
+ }
+ }
+
+ // QTBUG-73683
+ function test_rowlayoutWithTextItems() {
+ var layout = createTemporaryObject(rowlayoutWithTextItems_Component, container)
+ waitForRendering(layout)
+ for (var i = 0; i < 3; i++) {
+ ignoreWarning(/Qt Quick Layouts: Detected recursive rearrange. Aborting after two iterations./)
+ }
+ ignoreWarning(/Qt Quick Layouts: Polish loop detected. Aborting after two iterations./)
+ layout.width = layout.width - 2 // set the size to be smaller than its "minimum size"
+ waitForRendering(layout) // do not exit before all warnings have been received
+
+ // DO NOT CRASH due to stack overflow (or loop endlessly due to updatePolish()/polish() loop)
+ }
}
}