aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVladimir Belyavsky <belyavskyv@gmail.com>2026-03-28 01:34:08 +0300
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2026-04-23 04:57:09 +0000
commitd7109e4336dbbf5c11bc7ee441ef4b6930c24180 (patch)
treeb43b53086ec3514017a74f8f89367e2fb90b38e7
parentde25568e55fa2acd34dab63ef096477d3bd17a40 (diff)
QQuickText: fix inflated implicitWidth with maximumLineCount
When a Text element uses StyledText with <br> tags, maximumLineCount, wrapMode: Wrap, and elide: ElideRight, constraining its width could cause implicitWidth to grow far beyond the correct value. The root cause is twofold: 1. The loop that creates unwrapped lines for implicit width calculation used '<=' instead of '<', causing one extra line to be created and finalized beyond maximumLineCount paragraphs. 2. The multiline-elide code path creates a trailing line via createLine() to compute the elided text. That line is left unfinalized, so endLayout() finalizes it at QFIXED_MAX width, inflating maximumWidth(). Finalize it at zero width right after use. Fixes: QTBUG-142933 Change-Id: I64bab9512b8400ed63a4dda709259488a2b49a21 Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io> (cherry picked from commit 021778a0ad7d5758cee5f5592017e46b4e12171d) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/quick/items/qquicktext.cpp12
-rw-r--r--tests/auto/quick/qquicktext/tst_qquicktext.cpp39
2 files changed, 49 insertions, 2 deletions
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 22518ca5a5..5a65f170c4 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -980,12 +980,19 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
if (eos != -1) // There's an abbreviated string available
break;
- const QTextLine nextLine = layout.createLine();
+ QTextLine nextLine = layout.createLine();
elideText = wrappedLine
? elidedText(line.width(), line, &nextLine)
: elidedText(line.width(), line);
elideStart = line.textStart();
// elideEnd isn't required for right eliding.
+
+ // nextLine starts beyond maximumLineCount and is only
+ // needed for the elide calculation above. Finalize it
+ // at zero width so endLayout() won't give it QFIXED_MAX
+ // width, which would inflate maximumWidth().
+ if (nextLine.isValid())
+ nextLine.setLineWidth(0);
} else {
br = unelidedRect;
height = naturalHeight;
@@ -1024,9 +1031,10 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
: layoutText.size();
if (eol < layoutText.size() && layoutText.at(eol) != QChar::LineSeparator)
line = layout.createLine();
- for (; line.isValid() && unwrappedLineCount <= maxLineCount; ++unwrappedLineCount)
+ for (; line.isValid() && unwrappedLineCount < maxLineCount; ++unwrappedLineCount)
line = layout.createLine();
}
+
layout.endLayout();
const qreal naturalWidth = layout.maximumWidth();
diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
index 78b5d2220d..42ff11d99e 100644
--- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp
+++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
@@ -102,6 +102,7 @@ private slots:
void implicitSize();
void implicitSizeChangeRewrap();
void implicitSizeMaxLineCount();
+ void implicitWidthAfterWidthChange();
void dependentImplicitSizes();
void contentSize();
void implicitSizeBinding_data();
@@ -2487,6 +2488,44 @@ void tst_qquicktext::implicitSizeMaxLineCount()
QCOMPARE_EQ(textObject->implicitWidth(), referenceWidth);
}
+// implicitWidth should not grow after width is constrained and then released
+void tst_qquicktext::implicitWidthAfterWidthChange()
+{
+ // Test that implicitWidth remains stable when the item width is constrained
+ // and then released, for StyledText with <br> tags, maximumLineCount, wrap, and elide.
+ QScopedPointer<QQuickText> textObject(new QQuickText);
+ textObject->setTextFormat(QQuickText::StyledText);
+ textObject->setText(QStringLiteral("First line<br>Second line<br>"
+ "11111111111111111111111111111111111111111111111111111111111"
+ "11111111111111111111111111111111111111111"));
+ textObject->setMaximumLineCount(2);
+ textObject->setWrapMode(QQuickText::Wrap);
+ textObject->setElideMode(QQuickText::ElideRight);
+ textObject->componentComplete();
+
+ // Get the unconstrained implicitWidth
+ const qreal originalImplicitWidth = textObject->implicitWidth();
+ QVERIFY(originalImplicitWidth > 0);
+
+ // Constrain the width to something narrow enough to trigger wrapping
+ const qreal narrowWidth = originalImplicitWidth * 0.3;
+ textObject->setWidth(narrowWidth);
+
+ // The implicitWidth should not change just because we constrained the width
+ const qreal constrainedImplicitWidth = textObject->implicitWidth();
+ QCOMPARE_EQ(constrainedImplicitWidth, originalImplicitWidth);
+
+ // Now widen the width back
+ textObject->setWidth(originalImplicitWidth * 2);
+ const qreal widenedImplicitWidth = textObject->implicitWidth();
+ QCOMPARE_EQ(widenedImplicitWidth, originalImplicitWidth);
+
+ // Release the width constraint entirely
+ textObject->resetWidth();
+ const qreal afterImplicitWidth = textObject->implicitWidth();
+ QCOMPARE_EQ(afterImplicitWidth, originalImplicitWidth);
+}
+
void tst_qquicktext::dependentImplicitSizes()
{
QQmlComponent component(&engine, testFile("implicitSizes.qml"));