Hide default-invisible characters when shaping is disabled

When shaping is disabled we also skipped the step which set
dontPrint to true for soft hyphens, line separators, and
similar characters. This caused boxes to appear in text with
e.g. line separators.

There is a minor modification to the code that is moved:
In the case on unshaped text and only the CMAP able is used,
the font engine for the soft hyphen can be a fallback engine,
so we need to also set the correct engine index when changing
the glyph index.

[ChangeLog][QtGui][Text] Fixed an issue with QFont::PreferNoShaping
where boxes would appear in place of unprintable characters.

Fixes: QTBUG-81994
Change-Id: Ifc9f4f89d928475ca0487a92b4480bd5db5918fd
Reviewed-by: Konstantin Ritt <ritt.ks@gmail.com>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
bb10
Eskil Abrahamsen Blomfeldt 2020-03-05 09:26:42 +01:00
parent 6dbe03c4d1
commit 36325f9d86
1 changed files with 46 additions and 25 deletions

View File

@ -1358,6 +1358,37 @@ void QTextEngine::shapeLine(const QScriptLine &line)
extern bool qt_useHarfbuzzNG(); // defined in qfontengine.cpp
#endif
static void applyVisibilityRules(ushort ucs, QGlyphLayout *glyphs, uint glyphPosition, QFontEngine *fontEngine)
{
// hide characters that should normally be invisible
switch (ucs) {
case QChar::LineFeed:
case 0x000c: // FormFeed
case QChar::CarriageReturn:
case QChar::LineSeparator:
case QChar::ParagraphSeparator:
glyphs->attributes[glyphPosition].dontPrint = true;
break;
case QChar::SoftHyphen:
if (!fontEngine->symbol) {
// U+00AD [SOFT HYPHEN] is a default ignorable codepoint,
// so we replace its glyph and metrics with ones for
// U+002D [HYPHEN-MINUS] and make it visible if it appears at line-break
const uint engineIndex = glyphs->glyphs[glyphPosition] & 0xff000000;
glyphs->glyphs[glyphPosition] = fontEngine->glyphIndex('-');
if (Q_LIKELY(glyphs->glyphs[glyphPosition] != 0)) {
glyphs->glyphs[glyphPosition] |= engineIndex;
QGlyphLayout tmp = glyphs->mid(glyphPosition, 1);
fontEngine->recalcAdvances(&tmp, { });
}
glyphs->attributes[glyphPosition].dontPrint = true;
}
break;
default:
break;
}
}
void QTextEngine::shapeText(int item) const
{
Q_ASSERT(item < layoutData->items.size());
@ -1491,6 +1522,20 @@ void QTextEngine::shapeText(int item) const
&& QChar::isLowSurrogate(string[i + 1])) {
++i;
log_clusters[i] = glyph_pos;
initialGlyphs.attributes[glyph_pos].dontPrint = !QChar::isPrint(QChar::surrogateToUcs4(string[i], string[i + 1]));
} else {
initialGlyphs.attributes[glyph_pos].dontPrint = !QChar::isPrint(string[i]);
}
if (Q_UNLIKELY(!initialGlyphs.attributes[glyph_pos].dontPrint)) {
QFontEngine *actualFontEngine = fontEngine;
if (actualFontEngine->type() == QFontEngine::Multi) {
const uint engineIdx = initialGlyphs.glyphs[glyph_pos] >> 24;
actualFontEngine = static_cast<QFontEngineMulti *>(fontEngine)->engine(engineIdx);
}
applyVisibilityRules(string[i], &initialGlyphs, glyph_pos, actualFontEngine);
}
}
@ -1702,31 +1747,7 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si,
last_glyph_pos = i + glyphs_shaped;
last_cluster = cluster;
// hide characters that should normally be invisible
switch (string[item_pos + str_pos]) {
case QChar::LineFeed:
case 0x000c: // FormFeed
case QChar::CarriageReturn:
case QChar::LineSeparator:
case QChar::ParagraphSeparator:
g.attributes[i].dontPrint = true;
break;
case QChar::SoftHyphen:
if (!actualFontEngine->symbol) {
// U+00AD [SOFT HYPHEN] is a default ignorable codepoint,
// so we replace its glyph and metrics with ones for
// U+002D [HYPHEN-MINUS] and make it visible if it appears at line-break
g.glyphs[i] = actualFontEngine->glyphIndex('-');
if (Q_LIKELY(g.glyphs[i] != 0)) {
QGlyphLayout tmp = g.mid(i, 1);
actualFontEngine->recalcAdvances(&tmp, { });
}
g.attributes[i].dontPrint = true;
}
break;
default:
break;
}
applyVisibilityRules(string[item_pos + str_pos], &g, i, actualFontEngine);
}
}
while (str_pos < item_length)