From 36325f9d86249a4f17f7efbbc1122c462708d909 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 5 Mar 2020 09:26:42 +0100 Subject: [PATCH] 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 Reviewed-by: Lars Knoll --- src/gui/text/qtextengine.cpp | 71 +++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 25 deletions(-) diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 81ed8fa97a..26e8141184 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -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(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)