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>
This commit is contained in:
parent
b2ed29b8d9
commit
991c056438
@ -2604,6 +2604,7 @@ QTextEngine::LayoutData::LayoutData()
|
|||||||
haveCharAttributes = false;
|
haveCharAttributes = false;
|
||||||
logClustersPtr = nullptr;
|
logClustersPtr = nullptr;
|
||||||
available_glyphs = 0;
|
available_glyphs = 0;
|
||||||
|
currentMaxWidth = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QTextEngine::LayoutData::LayoutData(const QString &str, void **stack_memory, int _allocated)
|
QTextEngine::LayoutData::LayoutData(const QString &str, void **stack_memory, int _allocated)
|
||||||
@ -2636,6 +2637,7 @@ QTextEngine::LayoutData::LayoutData(const QString &str, void **stack_memory, int
|
|||||||
hasBidi = false;
|
hasBidi = false;
|
||||||
layoutState = LayoutEmpty;
|
layoutState = LayoutEmpty;
|
||||||
haveCharAttributes = false;
|
haveCharAttributes = false;
|
||||||
|
currentMaxWidth = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QTextEngine::LayoutData::~LayoutData()
|
QTextEngine::LayoutData::~LayoutData()
|
||||||
@ -2721,6 +2723,7 @@ void QTextEngine::freeMemory()
|
|||||||
layoutData->hasBidi = false;
|
layoutData->hasBidi = false;
|
||||||
layoutData->layoutState = LayoutEmpty;
|
layoutData->layoutState = LayoutEmpty;
|
||||||
layoutData->haveCharAttributes = false;
|
layoutData->haveCharAttributes = false;
|
||||||
|
layoutData->currentMaxWidth = 0;
|
||||||
layoutData->items.clear();
|
layoutData->items.clear();
|
||||||
}
|
}
|
||||||
if (specialData)
|
if (specialData)
|
||||||
|
@ -385,6 +385,7 @@ public:
|
|||||||
uint layoutState : 2;
|
uint layoutState : 2;
|
||||||
uint memory_on_stack : 1;
|
uint memory_on_stack : 1;
|
||||||
uint haveCharAttributes : 1;
|
uint haveCharAttributes : 1;
|
||||||
|
QFixed currentMaxWidth;
|
||||||
QString string;
|
QString string;
|
||||||
bool reallocate(int totalGlyphs);
|
bool reallocate(int totalGlyphs);
|
||||||
};
|
};
|
||||||
|
@ -1865,6 +1865,7 @@ void QTextLine::layout_helper(int maxGlyphs)
|
|||||||
lbh.logClusters = eng->layoutData->logClustersPtr;
|
lbh.logClusters = eng->layoutData->logClustersPtr;
|
||||||
lbh.previousGlyph = 0;
|
lbh.previousGlyph = 0;
|
||||||
|
|
||||||
|
bool manuallyWrapped = false;
|
||||||
bool hasInlineObject = false;
|
bool hasInlineObject = false;
|
||||||
QFixed maxInlineObjectHeight = 0;
|
QFixed maxInlineObjectHeight = 0;
|
||||||
|
|
||||||
@ -1940,6 +1941,7 @@ void QTextLine::layout_helper(int maxGlyphs)
|
|||||||
lbh.calculateRightBearingForPreviousGlyph();
|
lbh.calculateRightBearingForPreviousGlyph();
|
||||||
}
|
}
|
||||||
line += lbh.tmpData;
|
line += lbh.tmpData;
|
||||||
|
manuallyWrapped = true;
|
||||||
goto found;
|
goto found;
|
||||||
} else if (current.analysis.flags == QScriptAnalysis::Object) {
|
} else if (current.analysis.flags == QScriptAnalysis::Object) {
|
||||||
lbh.whiteSpaceOrObject = true;
|
lbh.whiteSpaceOrObject = true;
|
||||||
@ -1974,11 +1976,10 @@ void QTextLine::layout_helper(int maxGlyphs)
|
|||||||
addNextCluster(lbh.currentPosition, end, lbh.spaceData, lbh.glyphCount,
|
addNextCluster(lbh.currentPosition, end, lbh.spaceData, lbh.glyphCount,
|
||||||
current, lbh.logClusters, lbh.glyphs);
|
current, lbh.logClusters, lbh.glyphs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lbh.manualWrap && lbh.spaceData.textWidth > line.width) {
|
|
||||||
goto found;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
if (!lbh.manualWrap && lbh.spaceData.textWidth > line.width)
|
||||||
|
goto found;
|
||||||
|
|
||||||
lbh.whiteSpaceOrObject = false;
|
lbh.whiteSpaceOrObject = false;
|
||||||
bool sb_or_ws = false;
|
bool sb_or_ws = false;
|
||||||
lbh.saveCurrentGlyph();
|
lbh.saveCurrentGlyph();
|
||||||
@ -2161,7 +2162,12 @@ found:
|
|||||||
eng->maxWidth = qMax(eng->maxWidth, line.textWidth);
|
eng->maxWidth = qMax(eng->maxWidth, line.textWidth);
|
||||||
} else {
|
} else {
|
||||||
eng->minWidth = qMax(eng->minWidth, lbh.minw);
|
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;
|
line.textWidth += trailingSpace;
|
||||||
|
@ -2655,17 +2655,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("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("QTBUG-106947") << QStringLiteral("text text");
|
||||||
QTest::newRow("spaces") << 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()
|
void tst_QTextLayout::min_maximumWidth()
|
||||||
{
|
{
|
||||||
QFETCH(QString, text);
|
QFETCH(QString, text);
|
||||||
|
text.replace('\n', QChar::LineSeparator);
|
||||||
|
|
||||||
QTextLayout layout(text, testFont);
|
QTextLayout layout(text, testFont);
|
||||||
layout.setCacheEnabled(true);
|
layout.setCacheEnabled(true);
|
||||||
|
|
||||||
for (int wrapMode = QTextOption::NoWrap; wrapMode <= QTextOption::WrapAtWordBoundaryOrAnywhere; ++wrapMode) {
|
|
||||||
QTextOption opt;
|
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) {
|
||||||
opt.setWrapMode((QTextOption::WrapMode)wrapMode);
|
opt.setWrapMode((QTextOption::WrapMode)wrapMode);
|
||||||
layout.setTextOption(opt);
|
layout.setTextOption(opt);
|
||||||
layout.beginLayout();
|
layout.beginLayout();
|
||||||
@ -2674,6 +2685,9 @@ void tst_QTextLayout::min_maximumWidth()
|
|||||||
const qreal minWidth = layout.minimumWidth();
|
const qreal minWidth = layout.minimumWidth();
|
||||||
const qreal maxWidth = layout.maximumWidth();
|
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)
|
// Try the layout from slightly wider than the widest (maxWidth)
|
||||||
// and narrow it down to slighly narrower than minWidth
|
// and narrow it down to slighly narrower than minWidth
|
||||||
// layout.maximumWidth() should return the same regardless
|
// layout.maximumWidth() should return the same regardless
|
||||||
|
Loading…
x
Reference in New Issue
Block a user