Don't include bearing of mid-string characters in max width

When calculating the maximum width of a text layout, we
would add the text width of each substring *after* we had
added the negative right bearing of the last character to it.
But the bearing of the last character in a wrapped substring
does not actually add to the maximum width unless it is the
last character of the *whole* string.

Prior to 250117086ff15bba79df8f0e15ee66192edc9ea9 this was
not noticed, because the last glyph in the substring would
typically be a space and the space does not have any
bearings (when doing wrapping on individual characters it
could still happen). After the change, the previous glyph
for which we get the right bearing will be the last
non-whitespace glyph. If this happened to have a negative
right bearing, we would add this to the max width and
end up with a larger max width than we should.

This caused a test failure in tst_qquicktext.

This test prefers the text width without the bearing (i.e.
the *advance* of the substring) unless the line is manually
wrapped or it is the last line of the layout.

Pick-to: 6.8
Change-Id: Iba1a5ad48d575683672400f0572dfa683a0f2d9c
Reviewed-by: Lars Knoll <lars@knoll.priv.no>
(cherry picked from commit c08a92307d6d9fa9d9d9a1f301e3f2a65374e99a)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Eskil Abrahamsen Blomfeldt 2024-12-20 10:30:41 +01:00 committed by Qt Cherry-pick Bot
parent e266949979
commit 610ee0c504
2 changed files with 47 additions and 1 deletions

View File

@ -1860,6 +1860,7 @@ void QTextLine::layout_helper(int maxGlyphs)
bool manuallyWrapped = false; bool manuallyWrapped = false;
bool hasInlineObject = false; bool hasInlineObject = false;
bool reachedEndOfLine = false;
QFixed maxInlineObjectHeight = 0; QFixed maxInlineObjectHeight = 0;
const bool includeTrailingSpaces = eng->option.flags() & QTextOption::IncludeTrailingSpaces; const bool includeTrailingSpaces = eng->option.flags() & QTextOption::IncludeTrailingSpaces;
@ -2087,6 +2088,7 @@ void QTextLine::layout_helper(int maxGlyphs)
newItem = item + 1; newItem = item + 1;
} }
LB_DEBUG("reached end of line"); LB_DEBUG("reached end of line");
reachedEndOfLine = true;
lbh.checkFullOtherwiseExtend(line); lbh.checkFullOtherwiseExtend(line);
line.textWidth += lbh.commitedSoftHyphenWidth; line.textWidth += lbh.commitedSoftHyphenWidth;
found: found:
@ -2097,6 +2099,7 @@ found:
lbh.calculateRightBearing(); lbh.calculateRightBearing();
// Then apply any negative right bearing // Then apply any negative right bearing
const QFixed textWidthWithoutBearing = line.textWidth;
line.textWidth += lbh.negativeRightBearing(); line.textWidth += lbh.negativeRightBearing();
if (line.length == 0) { if (line.length == 0) {
@ -2168,7 +2171,11 @@ 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);
if (qAddOverflow(eng->layoutData->currentMaxWidth, line.textWidth, &eng->layoutData->currentMaxWidth))
const QFixed actualTextWidth = manuallyWrapped || reachedEndOfLine
? line.textWidth
: textWidthWithoutBearing;
if (qAddOverflow(eng->layoutData->currentMaxWidth, actualTextWidth, &eng->layoutData->currentMaxWidth))
eng->layoutData->currentMaxWidth = QFIXED_MAX; eng->layoutData->currentMaxWidth = QFIXED_MAX;
if (!manuallyWrapped) { if (!manuallyWrapped) {
if (qAddOverflow(eng->layoutData->currentMaxWidth, lbh.spaceData.textWidth, &eng->layoutData->currentMaxWidth)) if (qAddOverflow(eng->layoutData->currentMaxWidth, lbh.spaceData.textWidth, &eng->layoutData->currentMaxWidth))

View File

@ -130,6 +130,7 @@ private slots:
void negativeLineWidth(); void negativeLineWidth();
void embeddedImageLineHeight(); void embeddedImageLineHeight();
void unmatchedShapedSubstring(); void unmatchedShapedSubstring();
void maximumLayoutWidthInWrappedLayout();
private: private:
QFont testFont; QFont testFont;
@ -2836,5 +2837,43 @@ void tst_QTextLayout::unmatchedShapedSubstring()
QVERIFY(glyphRuns.size() > 0); QVERIFY(glyphRuns.size() > 0);
} }
void tst_QTextLayout::maximumLayoutWidthInWrappedLayout()
{
QString s = QString::fromUtf8("Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n"
"Integer at ante dui Curabitur ante est, pulvinar quis adipiscing a, iaculis id ipsum. Nunc blandit\n"
"condimentum odio vel egestas. in ipsum lacinia sit amet\n"
"mattis orci interdum. Quisque vitae accumsan lectus. Ut nisi turpis,\n"
"sollicitudin ut dignissim id, fermentum ac est. Maecenas nec libero leo. Sed ac\n"
"mattis orci interdum. Quisque vitae accumsan lectus. Ut nisi turpis,\n"
"sollicitudin ut dignissim id, fermentum ac est. Maecenas nec libero leo. Sed ac\n"
"leo eget ipsum ultricies viverra sit amet eu orci. Praesent et tortor risus,\n"
"viverra accumsan sapien. Sed faucibus eleifend lectus, sed euismod urna porta\n"
"eu. Quisque vitae accumsan lectus.");
s.replace(QChar::LineFeed, QChar::LineSeparator);
QTextLayout reference;
reference.setText(s);
reference.beginLayout();
forever {
QTextLine line = reference.createLine();
if (!line.isValid())
break;
}
reference.endLayout();
QTextLayout breakByWidth;
breakByWidth.setText(s);
breakByWidth.beginLayout();
forever {
QTextLine line = breakByWidth.createLine();
if (!line.isValid())
break;
line.setLineWidth(100);
}
breakByWidth.endLayout();
QCOMPARE(reference.maximumWidth(), breakByWidth.maximumWidth());
}
QTEST_MAIN(tst_QTextLayout) QTEST_MAIN(tst_QTextLayout)
#include "tst_qtextlayout.moc" #include "tst_qtextlayout.moc"