Handle macOS 11 issues in softHyphens test

Calculate the effective width of the hyphen better, and compare with
ceiled sizes.

Fixes: QTBUG-90698
Change-Id: I7ed2eb44c54240ecb2f8a38e5acf1f32608b2bfb
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
(cherry picked from commit 0ffdbb21261eee3a9ec1cd541478ee883a12065c)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Allan Sandfeld Jensen 2021-02-01 10:21:04 +01:00 committed by Qt Cherry-pick Bot
parent d95069771b
commit ac05ca5072
2 changed files with 50 additions and 19 deletions

View File

@ -1373,9 +1373,15 @@ static void applyVisibilityRules(ushort ucs, QGlyphLayout *glyphs, uint glyphPos
if (!fontEngine->symbol) { if (!fontEngine->symbol) {
// U+00AD [SOFT HYPHEN] is a default ignorable codepoint, // U+00AD [SOFT HYPHEN] is a default ignorable codepoint,
// so we replace its glyph and metrics with ones for // so we replace its glyph and metrics with ones for
// U+002D [HYPHEN-MINUS] and make it visible if it appears at line-break // U+002D [HYPHEN-MINUS] or U+2010 [HYPHEN] and make
// it visible if it appears at line-break
const uint engineIndex = glyphs->glyphs[glyphPosition] & 0xff000000; const uint engineIndex = glyphs->glyphs[glyphPosition] & 0xff000000;
glyphs->glyphs[glyphPosition] = fontEngine->glyphIndex('-'); glyph_t glyph = fontEngine->glyphIndex(0x002d);
if (glyph == 0)
glyph = fontEngine->glyphIndex(0x2010);
if (glyph == 0)
glyph = fontEngine->glyphIndex(0x00ad);
glyphs->glyphs[glyphPosition] = glyph;
if (Q_LIKELY(glyphs->glyphs[glyphPosition] != 0)) { if (Q_LIKELY(glyphs->glyphs[glyphPosition] != 0)) {
glyphs->glyphs[glyphPosition] |= engineIndex; glyphs->glyphs[glyphPosition] |= engineIndex;
QGlyphLayout tmp = glyphs->mid(glyphPosition, 1); QGlyphLayout tmp = glyphs->mid(glyphPosition, 1);

View File

@ -141,6 +141,7 @@ private slots:
void showLineAndParagraphSeparatorsCrash(); void showLineAndParagraphSeparatorsCrash();
void koreanWordWrap(); void koreanWordWrap();
void tooManyDirectionalCharctersCrash_qtbug77819(); void tooManyDirectionalCharctersCrash_qtbug77819();
void softHyphens_data();
void softHyphens(); void softHyphens();
void min_maximumWidth(); void min_maximumWidth();
@ -2414,22 +2415,45 @@ void tst_QTextLayout::tooManyDirectionalCharctersCrash_qtbug77819()
tl.endLayout(); tl.endLayout();
} }
void tst_QTextLayout::softHyphens_data()
{
QTest::addColumn<int>("fontSize");
QTest::newRow("12") << 12;
QTest::newRow("14") << 14;
QTest::newRow("16") << 16;
}
void tst_QTextLayout::softHyphens() void tst_QTextLayout::softHyphens()
{ {
QFETCH(int, fontSize);
QString text = QStringLiteral("xxxx\u00ad") + QStringLiteral("xxxx\u00ad"); QString text = QStringLiteral("xxxx\u00ad") + QStringLiteral("xxxx\u00ad");
QFont font; QFont font;
font.setPixelSize(14); font.setPixelSize(fontSize);
font.setHintingPreference(QFont::PreferNoHinting); font.setHintingPreference(QFont::PreferNoHinting);
const float xAdvance = QFontMetricsF(font).horizontalAdvance(QChar('x')); const float xAdvance = QFontMetricsF(font).horizontalAdvance(QChar::fromLatin1('x'));
const float shyAdvance = QFontMetricsF(font).horizontalAdvance(QChar::SoftHyphen); float shyWidth = 0.0f;
if (xAdvance < (shyAdvance + 1.0f))
QSKIP("Default font not suitable for this test.");
QTextLayout layout(text, font); QTextLayout layout(text, font);
QTextOption option; QTextOption option;
option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
layout.setTextOption(option); layout.setTextOption(option);
{
// Calculate the effective width of a line-ending hyphen
// This calculation is currently done to work-around odditities on
// macOS 11 (see QTBUG-90698).
QTextLayout test(QStringLiteral("x\u00ad"), font);
// Note: This only works because Qt show the soft-hyphen when ending a text.
// This _could_ be considered a bug and the test would need to be changed
// if we stop doing that.
test.beginLayout();
QTextLine line = test.createLine();
line.setLineWidth(10 * xAdvance);
line.setPosition(QPoint(0, 0));
shyWidth = line.naturalTextWidth() - xAdvance;
test.endLayout();
}
qreal linefit;
// Loose fit // Loose fit
// xxxx- | // xxxx- |
// xxxx- | // xxxx- |
@ -2438,21 +2462,22 @@ void tst_QTextLayout::softHyphens()
int y = 0; int y = 0;
layout.beginLayout(); layout.beginLayout();
QTextLine line = layout.createLine(); QTextLine line = layout.createLine();
line.setLineWidth(qCeil(5 * xAdvance) + 1); line.setLineWidth(qCeil(5 * xAdvance + shyWidth) + 1);
line.setPosition(QPoint(0, y)); line.setPosition(QPoint(0, y));
QCOMPARE(line.textStart(), pos); QCOMPARE(line.textStart(), pos);
QCOMPARE(line.textLength(), 5); QCOMPARE(line.textLength(), 5);
QVERIFY(qAbs(line.naturalTextWidth() - (4 * xAdvance + shyAdvance)) <= 1); linefit = line.naturalTextWidth();
QVERIFY(qAbs(linefit - qCeil(4 * xAdvance + shyWidth)) <= 1.0);
pos += line.textLength(); pos += line.textLength();
y += qRound(line.ascent() + line.descent()); y += qRound(line.ascent() + line.descent());
line = layout.createLine(); line = layout.createLine();
line.setLineWidth(qCeil(5 * xAdvance) + 1); line.setLineWidth(qCeil(5 * xAdvance + shyWidth) + 1);
line.setPosition(QPoint(0, y)); line.setPosition(QPoint(0, y));
QCOMPARE(line.textStart(), pos); QCOMPARE(line.textStart(), pos);
QCOMPARE(line.textLength(), 5); QCOMPARE(line.textLength(), 5);
QVERIFY(qAbs(line.naturalTextWidth() - (4 * xAdvance + shyAdvance)) <= 1); QVERIFY(qAbs(line.naturalTextWidth() - linefit) <= 1.0);
layout.endLayout(); layout.endLayout();
} }
@ -2464,21 +2489,21 @@ void tst_QTextLayout::softHyphens()
int y = 0; int y = 0;
layout.beginLayout(); layout.beginLayout();
QTextLine line = layout.createLine(); QTextLine line = layout.createLine();
line.setLineWidth(qCeil(4 * xAdvance + shyAdvance) + 1); line.setLineWidth(qCeil(linefit) + 1);
line.setPosition(QPoint(0, y)); line.setPosition(QPoint(0, y));
QCOMPARE(line.textStart(), pos); QCOMPARE(line.textStart(), pos);
QCOMPARE(line.textLength(), 5); QCOMPARE(line.textLength(), 5);
QVERIFY(qAbs(line.naturalTextWidth() - (4 * xAdvance + shyAdvance)) <= 1); QVERIFY(qAbs(line.naturalTextWidth() - linefit) <= 1.0);
pos += line.textLength(); pos += line.textLength();
y += qRound(line.ascent() + line.descent()); y += qRound(line.ascent() + line.descent());
line = layout.createLine(); line = layout.createLine();
line.setLineWidth(qCeil(4 * xAdvance + shyAdvance) + 1); line.setLineWidth(qCeil(linefit) + 1);
line.setPosition(QPoint(0, y)); line.setPosition(QPoint(0, y));
QCOMPARE(line.textStart(), pos); QCOMPARE(line.textStart(), pos);
QCOMPARE(line.textLength(), 5); QCOMPARE(line.textLength(), 5);
QVERIFY(qAbs(line.naturalTextWidth() - (4 * xAdvance + shyAdvance)) <= 1); QVERIFY(qAbs(line.naturalTextWidth() - linefit) <= 1.0);
layout.endLayout(); layout.endLayout();
} }
@ -2495,7 +2520,7 @@ void tst_QTextLayout::softHyphens()
line.setPosition(QPoint(0, y)); line.setPosition(QPoint(0, y));
QCOMPARE(line.textStart(), pos); QCOMPARE(line.textStart(), pos);
QCOMPARE(line.textLength(), 4); QCOMPARE(line.textLength(), 4);
QVERIFY(qAbs(line.naturalTextWidth() - 4 * xAdvance) <= 1); QVERIFY(qAbs(line.naturalTextWidth() - qCeil(4 * xAdvance)) <= 1.0);
pos += line.textLength(); pos += line.textLength();
y += qRound(line.ascent() + line.descent()); y += qRound(line.ascent() + line.descent());
@ -2505,7 +2530,7 @@ void tst_QTextLayout::softHyphens()
line.setPosition(QPoint(0, y)); line.setPosition(QPoint(0, y));
QCOMPARE(line.textStart(), pos); QCOMPARE(line.textStart(), pos);
QCOMPARE(line.textLength(), 5); QCOMPARE(line.textLength(), 5);
QVERIFY(qAbs(line.naturalTextWidth() - 4 * xAdvance) <= 1); QVERIFY(qAbs(line.naturalTextWidth() - qCeil(4 * xAdvance)) <= 1.0);
pos += line.textLength(); pos += line.textLength();
y += qRound(line.ascent() + line.descent()); y += qRound(line.ascent() + line.descent());
@ -2515,7 +2540,7 @@ void tst_QTextLayout::softHyphens()
line.setPosition(QPoint(0, y)); line.setPosition(QPoint(0, y));
QCOMPARE(line.textStart(), pos); QCOMPARE(line.textStart(), pos);
QCOMPARE(line.textLength(), 1); QCOMPARE(line.textLength(), 1);
QVERIFY(qAbs(line.naturalTextWidth() - shyAdvance) <= 1); QVERIFY(qAbs(line.naturalTextWidth() - shyWidth) <= 1.0);
layout.endLayout(); layout.endLayout();
} }
} }