123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- From b58616bff6715a6c66bdc9019d008b7918d3ccc8 Mon Sep 17 00:00:00 2001
- From: Vladimir Belyavsky <belyavskyv@gmail.com>
- Date: Tue, 27 Sep 2022 16:57:08 +0300
- Subject: [PATCH] QTextLayout: fix maximumWidth() for a text containing line
- separator
- This is improved version of previous fix
- 013c346a8dcbd618febb07884c64c740daf9754d that was reverted because it
- broke some tests for Quick Text. The problem was that it did not work
- correctly in the case the text was wrapped to a fixed width.
- To deal with this we'll accumulate current line full width (as if it
- hadn't been wrapped) in layout data (layoutData->currentMaxWidth).
- Then when the next line is explicitly wrapped by line or paragraph
- separator, this accumulated width will be used to adjust layout's
- maximum width.
- Change-Id: Iad7119d9808e1db15fe1fbc5db049c3db928529f
- Fixes: QTBUG-89557
- Fixes: QTBUG-104986
- Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
- Upstream: https://github.com/qt/qtbase/commit/991c056438b311566bc4ea543af0f33dfd5dffbb
- [Thomas: Needed to backport fix for
- https://security-tracker.debian.org/tracker/CVE-2023-32763]
- Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
- ---
- src/gui/text/qtextengine.cpp | 3 +++
- src/gui/text/qtextengine_p.h | 1 +
- src/gui/text/qtextlayout.cpp | 16 +++++++++++-----
- .../gui/text/qtextlayout/tst_qtextlayout.cpp | 16 +++++++++++++++-
- 4 files changed, 30 insertions(+), 6 deletions(-)
- diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
- index ec528760e3b..ef3cdcbaaa7 100644
- --- a/src/gui/text/qtextengine.cpp
- +++ b/src/gui/text/qtextengine.cpp
- @@ -2619,6 +2619,7 @@ QTextEngine::LayoutData::LayoutData()
- haveCharAttributes = false;
- logClustersPtr = nullptr;
- available_glyphs = 0;
- + currentMaxWidth = 0;
- }
-
- QTextEngine::LayoutData::LayoutData(const QString &str, void **stack_memory, int _allocated)
- @@ -2651,6 +2652,7 @@ QTextEngine::LayoutData::LayoutData(const QString &str, void **stack_memory, int
- hasBidi = false;
- layoutState = LayoutEmpty;
- haveCharAttributes = false;
- + currentMaxWidth = 0;
- }
-
- QTextEngine::LayoutData::~LayoutData()
- @@ -2736,6 +2738,7 @@ void QTextEngine::freeMemory()
- layoutData->hasBidi = false;
- layoutData->layoutState = LayoutEmpty;
- layoutData->haveCharAttributes = false;
- + layoutData->currentMaxWidth = 0;
- layoutData->items.clear();
- }
- if (specialData)
- diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h
- index 925dafe04e2..59e332c64ae 100644
- --- a/src/gui/text/qtextengine_p.h
- +++ b/src/gui/text/qtextengine_p.h
- @@ -385,6 +385,7 @@ public:
- uint layoutState : 2;
- uint memory_on_stack : 1;
- uint haveCharAttributes : 1;
- + QFixed currentMaxWidth;
- QString string;
- bool reallocate(int totalGlyphs);
- };
- diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
- index 9ae6bee2de3..2009dd3d0bb 100644
- --- a/src/gui/text/qtextlayout.cpp
- +++ b/src/gui/text/qtextlayout.cpp
- @@ -1808,6 +1808,7 @@ void QTextLine::layout_helper(int maxGlyphs)
- lbh.logClusters = eng->layoutData->logClustersPtr;
- lbh.previousGlyph = 0;
-
- + bool manuallyWrapped = false;
- bool hasInlineObject = false;
- QFixed maxInlineObjectHeight = 0;
-
- @@ -1883,6 +1884,7 @@ void QTextLine::layout_helper(int maxGlyphs)
- lbh.calculateRightBearingForPreviousGlyph();
- }
- line += lbh.tmpData;
- + manuallyWrapped = true;
- goto found;
- } else if (current.analysis.flags == QScriptAnalysis::Object) {
- lbh.whiteSpaceOrObject = true;
- @@ -1917,11 +1919,10 @@ void QTextLine::layout_helper(int maxGlyphs)
- addNextCluster(lbh.currentPosition, end, lbh.spaceData, lbh.glyphCount,
- current, lbh.logClusters, lbh.glyphs);
- }
- -
- - if (!lbh.manualWrap && lbh.spaceData.textWidth > line.width) {
- - goto found;
- - }
- } else {
- + if (!lbh.manualWrap && lbh.spaceData.textWidth > line.width)
- + goto found;
- +
- lbh.whiteSpaceOrObject = false;
- bool sb_or_ws = false;
- lbh.saveCurrentGlyph();
- @@ -2104,7 +2105,12 @@ found:
- eng->maxWidth = qMax(eng->maxWidth, line.textWidth);
- } else {
- eng->minWidth = qMax(eng->minWidth, lbh.minw);
- - eng->maxWidth += line.textWidth + lbh.spaceData.textWidth;
- + eng->layoutData->currentMaxWidth += line.textWidth;
- + if (!manuallyWrapped)
- + eng->layoutData->currentMaxWidth += lbh.spaceData.textWidth;
- + eng->maxWidth = qMax(eng->maxWidth, eng->layoutData->currentMaxWidth);
- + if (manuallyWrapped)
- + eng->layoutData->currentMaxWidth = 0;
- }
-
- line.textWidth += trailingSpace;
- diff --git a/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp
- index 680c62e9825..5b14c4e1491 100644
- --- a/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp
- +++ b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp
- @@ -2670,17 +2670,28 @@ void tst_QTextLayout::min_maximumWidth_data()
- QTest::newRow("long string") << QStringLiteral("lmong_long_crazy_87235982735_23857239682376923876923876-fuwhfhfw-names-AAAA-deeaois2019-03-03.and.more");
- QTest::newRow("QTBUG-106947") << QStringLiteral("text text");
- QTest::newRow("spaces") << QStringLiteral(" text text ");
- + QTest::newRow("QTBUG-104986") << QStringLiteral("text\ntext\ntext");
- + QTest::newRow("spaces + line breaks") << QStringLiteral(" \n text\n \ntext \n ");
- }
-
- void tst_QTextLayout::min_maximumWidth()
- {
- QFETCH(QString, text);
- + text.replace('\n', QChar::LineSeparator);
-
- QTextLayout layout(text, testFont);
- layout.setCacheEnabled(true);
-
- + QTextOption opt;
- + opt.setWrapMode(QTextOption::NoWrap);
- + layout.setTextOption(opt);
- + layout.beginLayout();
- + while (layout.createLine().isValid()) { }
- + layout.endLayout();
- +
- + const qreal nonWrappedMaxWidth = layout.maximumWidth();
- +
- for (int wrapMode = QTextOption::NoWrap; wrapMode <= QTextOption::WrapAtWordBoundaryOrAnywhere; ++wrapMode) {
- - QTextOption opt;
- opt.setWrapMode((QTextOption::WrapMode)wrapMode);
- layout.setTextOption(opt);
- layout.beginLayout();
- @@ -2689,6 +2700,9 @@ void tst_QTextLayout::min_maximumWidth()
- const qreal minWidth = layout.minimumWidth();
- const qreal maxWidth = layout.maximumWidth();
-
- + QCOMPARE_LE(minWidth, maxWidth);
- + QCOMPARE_LE(maxWidth, nonWrappedMaxWidth); // maxWidth for wrapped text shouldn't exceed maxWidth for the text without wrapping.
- +
- // Try the layout from slightly wider than the widest (maxWidth)
- // and narrow it down to slighly narrower than minWidth
- // layout.maximumWidth() should return the same regardless
- --
- 2.46.0
|