aboutsummaryrefslogtreecommitdiffstats
path: root/src/imports/layouts/qquicklayout.cpp
diff options
context:
space:
mode:
authorJan Arve Sæther <jan-arve.saether@qt.io>2019-11-22 17:03:43 +0100
committerJan Arve Sæther <jan-arve.saether@qt.io>2020-02-12 12:55:44 +0100
commit70120c931faa0c6139354c75fcf8d39b77ec3b4a (patch)
treed29759955e83724f35d19973a05e1db1815f210a /src/imports/layouts/qquicklayout.cpp
parent2f4c131805f4009f42abe991e0f92f096bbc55fd (diff)
Fix a bug where a layout could crash or become non-responsive
This happened because of that QQuickText is ill-behaving: When the width on a QQuickText with word wrap enabled is changed to something less than its implicitWidth, its implicitHeight is changed to reflect the height it needs in order to fit all lines. This will cause the layout to be invalidated, and rearranged again. However, at the same time it will also change its implicitWidth actually become wider than its initial implicitWidth (this seems to be a bug). So the next time it is rearranged it will actually be wide enough so that it doesn't need to wrap. This again will cause its implicitWidth and implicitHeight to change to reflect that only one line is needed, which again will cause it to rearrange, but since the item has a too small width for that it will again change the implicitHeight to reflect that it needs more lines..... This went on forever until there was a stack overflow. In addition it also caused an endless (that is, if it didn't stack overflow) updatePolish()/polish() loop (basically polish() was called from within updatePolish() continuously). To make the layout more robust for such "ill-behaving" items we have to add one recursion guard, and one polish-loop guard. Change-Id: I9f752ed320a100c8d0f0fd340347a556e63318e5 Task-number: QTBUG-73683 Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
Diffstat (limited to 'src/imports/layouts/qquicklayout.cpp')
-rw-r--r--src/imports/layouts/qquicklayout.cpp21
1 files changed, 18 insertions, 3 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.";
}
}