diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/global/qnamespace.h | 7 | ||||
-rw-r--r-- | src/gui/painting/qpainter.cpp | 2 | ||||
-rw-r--r-- | src/gui/text/qfont.cpp | 5 | ||||
-rw-r--r-- | src/gui/text/qfont.h | 1 | ||||
-rw-r--r-- | src/gui/text/qfontengine.cpp | 4 | ||||
-rw-r--r-- | src/gui/text/qfontengine_p.h | 6 | ||||
-rw-r--r-- | src/gui/text/qfontmetrics.cpp | 2 | ||||
-rw-r--r-- | src/gui/text/qtextengine.cpp | 85 |
8 files changed, 78 insertions, 34 deletions
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index 9056eab2f1..fa3d5913b5 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -241,8 +241,11 @@ public: TextForceRightToLeft = 0x40000, // Ensures that the longest variant is always used when computing the // size of a multi-variant string. - TextLongestVariant = 0x80000, - TextBypassShaping = 0x100000 + TextLongestVariant = 0x80000 + +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + , TextBypassShaping = 0x100000 +#endif }; enum TextElideMode { diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index b186182c34..fb3c845e77 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5850,6 +5850,7 @@ void QPainter::drawText(const QPointF &p, const QString &str, int tf, int justif if (!d->engine || str.isEmpty() || pen().style() == Qt::NoPen) return; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) if (tf & Qt::TextBypassShaping) { // Skip complex shaping, shape using glyph advances only int len = str.length(); @@ -5863,6 +5864,7 @@ void QPainter::drawText(const QPointF &p, const QString &str, int tf, int justif drawTextItem(p, gf); return; } +#endif QStackTextEngine engine(str, d->state->font); engine.option.setTextDirection(d->state->layoutDirection); diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index 7f3ed3adaa..f0a5053196 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -1312,6 +1312,11 @@ QFont::StyleHint QFont::styleHint() const looking font that contains the character. The NoFontMerging flag disables this feature. Please note that enabling this flag will not prevent Qt from automatically picking a suitable font when the selected font does not support the writing system of the text. + \value PreferNoShaping Sometimes, a font will apply complex rules to a set of characters in + order to display them correctly. In some writing systems, such as Brahmic scripts, this is + required in order for the text to be legible, but in e.g. Latin script, it is merely + a cosmetic feature. The PreferNoShaping flag will disable all such features when they + are not required, which will improve performance in most cases. Any of these may be OR-ed with one of these flags: diff --git a/src/gui/text/qfont.h b/src/gui/text/qfont.h index 0f2bef9152..9c250c82c3 100644 --- a/src/gui/text/qfont.h +++ b/src/gui/text/qfont.h @@ -83,6 +83,7 @@ public: OpenGLCompatible = 0x0200, ForceIntegerMetrics = 0x0400, NoSubpixelAntialias = 0x0800, + PreferNoShaping = 0x1000, NoFontMerging = 0x8000 }; Q_ENUM(StyleStrategy) diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index 596c79fd05..e4f9b8b9d4 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -359,10 +359,8 @@ bool QFontEngine::supportsScript(QChar::Script script) const // ### TODO: This only works for scripts that require OpenType. More generally // for scripts that do not require OpenType we should just look at the list of // supported writing systems in the font's OS/2 table. - if (!((script >= QChar::Script_Syriac && script <= QChar::Script_Sinhala) - || script == QChar::Script_Khmer || script == QChar::Script_Nko)) { + if (!scriptRequiresOpenType(script)) return true; - } #if QT_CONFIG(harfbuzz) if (qt_useHarfbuzzNG()) { diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index 514e9424b2..1ae2e86a93 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -242,6 +242,12 @@ public: void *harfbuzzFace() const; bool supportsScript(QChar::Script script) const; + inline static bool scriptRequiresOpenType(QChar::Script script) + { + return ((script >= QChar::Script_Syriac && script <= QChar::Script_Sinhala) + || script == QChar::Script_Khmer || script == QChar::Script_Nko); + } + virtual int getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints); void clearGlyphCache(const void *key); diff --git a/src/gui/text/qfontmetrics.cpp b/src/gui/text/qfontmetrics.cpp index 8067969f56..5675d6921d 100644 --- a/src/gui/text/qfontmetrics.cpp +++ b/src/gui/text/qfontmetrics.cpp @@ -541,6 +541,7 @@ int QFontMetrics::width(const QString &text, int len, int flags) const if (len == 0) return 0; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) if (flags & Qt::TextBypassShaping) { // Skip complex shaping, only use advances int numGlyphs = len; @@ -554,6 +555,7 @@ int QFontMetrics::width(const QString &text, int len, int flags) const width += glyphs.advances[i]; return qRound(width); } +#endif QStackTextEngine layout(text, QFont(d.data())); return qRound(layout.width(0, len)); diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 4d24fb50af..a9d23d8e4b 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -1005,20 +1005,53 @@ void QTextEngine::shapeText(int item) const QFontEngine *fontEngine = this->fontEngine(si, &si.ascent, &si.descent, &si.leading); + bool kerningEnabled; + bool letterSpacingIsAbsolute; + bool shapingEnabled; + QFixed letterSpacing, wordSpacing; +#ifndef QT_NO_RAWFONT + if (useRawFont) { + QTextCharFormat f = format(&si); + kerningEnabled = f.fontKerning(); + shapingEnabled = QFontEngine::scriptRequiresOpenType(QChar::Script(si.analysis.script)) + || (f.fontStyleStrategy() & QFont::PreferNoShaping) == 0; + wordSpacing = QFixed::fromReal(f.fontWordSpacing()); + letterSpacing = QFixed::fromReal(f.fontLetterSpacing()); + letterSpacingIsAbsolute = true; + } else +#endif + { + QFont font = this->font(si); + kerningEnabled = font.d->kerning; + shapingEnabled = QFontEngine::scriptRequiresOpenType(QChar::Script(si.analysis.script)) + || (font.d->request.styleStrategy & QFont::PreferNoShaping) == 0; + letterSpacingIsAbsolute = font.d->letterSpacingIsAbsolute; + letterSpacing = font.d->letterSpacing; + wordSpacing = font.d->wordSpacing; + + if (letterSpacingIsAbsolute && letterSpacing.value()) + letterSpacing *= font.d->dpi / qt_defaultDpiY(); + } + // split up the item into parts that come from different font engines // k * 3 entries, array[k] == index in string, array[k + 1] == index in glyphs, array[k + 2] == engine index QVector<uint> itemBoundaries; itemBoundaries.reserve(24); - if (fontEngine->type() == QFontEngine::Multi) { + + QGlyphLayout initialGlyphs = availableGlyphs(&si); + int nGlyphs = initialGlyphs.numGlyphs; + if (fontEngine->type() == QFontEngine::Multi || !shapingEnabled) { // ask the font engine to find out which glyphs (as an index in the specific font) // to use for the text in one item. - QGlyphLayout initialGlyphs = availableGlyphs(&si); - - int nGlyphs = initialGlyphs.numGlyphs; - QFontEngine::ShaperFlags shaperFlags(QFontEngine::GlyphIndicesOnly); + QFontEngine::ShaperFlags shaperFlags = + shapingEnabled + ? QFontEngine::GlyphIndicesOnly + : QFontEngine::ShaperFlag(0); if (!fontEngine->stringToCMap(reinterpret_cast<const QChar *>(string), itemLength, &initialGlyphs, &nGlyphs, shaperFlags)) Q_UNREACHABLE(); + } + if (fontEngine->type() == QFontEngine::Multi) { uint lastEngine = ~0u; for (int i = 0, glyph_pos = 0; i < itemLength; ++i, ++glyph_pos) { const uint engineIdx = initialGlyphs.glyphs[glyph_pos] >> 24; @@ -1046,35 +1079,29 @@ void QTextEngine::shapeText(int item) const itemBoundaries.append(0); } - bool kerningEnabled; - bool letterSpacingIsAbsolute; - QFixed letterSpacing, wordSpacing; -#ifndef QT_NO_RAWFONT - if (useRawFont) { - QTextCharFormat f = format(&si); - kerningEnabled = f.fontKerning(); - wordSpacing = QFixed::fromReal(f.fontWordSpacing()); - letterSpacing = QFixed::fromReal(f.fontLetterSpacing()); - letterSpacingIsAbsolute = true; - } else -#endif - { - QFont font = this->font(si); - kerningEnabled = font.d->kerning; - letterSpacingIsAbsolute = font.d->letterSpacingIsAbsolute; - letterSpacing = font.d->letterSpacing; - wordSpacing = font.d->wordSpacing; + if (Q_UNLIKELY(!shapingEnabled)) { + ushort *log_clusters = logClusters(&si); - if (letterSpacingIsAbsolute && letterSpacing.value()) - letterSpacing *= font.d->dpi / qt_defaultDpiY(); - } + int glyph_pos = 0; + for (int i = 0; i < itemLength; ++i, ++glyph_pos) { + log_clusters[i] = glyph_pos; + initialGlyphs.attributes[glyph_pos].clusterStart = true; + if (QChar::isHighSurrogate(string[i]) + && i + 1 < itemLength + && QChar::isLowSurrogate(string[i + 1])) { + ++i; + log_clusters[i] = glyph_pos; + } + } + si.num_glyphs = glyph_pos; #if QT_CONFIG(harfbuzz) - if (Q_LIKELY(qt_useHarfbuzzNG())) + } else if (Q_LIKELY(qt_useHarfbuzzNG())) { si.num_glyphs = shapeTextWithHarfbuzzNG(si, string, itemLength, fontEngine, itemBoundaries, kerningEnabled, letterSpacing != 0); - else #endif - si.num_glyphs = shapeTextWithHarfbuzz(si, string, itemLength, fontEngine, itemBoundaries, kerningEnabled); + } else { + si.num_glyphs = shapeTextWithHarfbuzz(si, string, itemLength, fontEngine, itemBoundaries, kerningEnabled); + } if (Q_UNLIKELY(si.num_glyphs == 0)) { Q_UNREACHABLE(); // ### report shaping errors somehow return; |