diff options
| author | Vladimir Belyavsky <belyavskyv@gmail.com> | 2026-03-28 01:34:08 +0300 |
|---|---|---|
| committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2026-04-23 04:57:09 +0000 |
| commit | d7109e4336dbbf5c11bc7ee441ef4b6930c24180 (patch) | |
| tree | b43b53086ec3514017a74f8f89367e2fb90b38e7 | |
| parent | de25568e55fa2acd34dab63ef096477d3bd17a40 (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.cpp | 12 | ||||
| -rw-r--r-- | tests/auto/quick/qquicktext/tst_qquicktext.cpp | 39 |
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")); |
