diff options
author | Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io> | 2017-07-03 11:30:43 +0200 |
---|---|---|
committer | Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io> | 2017-07-26 10:51:00 +0000 |
commit | 73176d2922baae1ccaa702e4900b0473071d0a96 (patch) | |
tree | fc049297630455d6ea0b7f4161acfba610aed2d1 /src/gui/text/qtextengine.cpp | |
parent | 8719660416986702c1ee9f65c4e347efa37ac770 (diff) |
Add API to disable text shaping on fonts
In the past, we had an undocumented text flag that worked with
one of the QPainter::drawText() overloads. This was never intended
as public API and served a specific cause in Qt WebKit at one point.
But there is a general need for such API, as disabling shaping features
easily gives 25% performance improvement on text rendering even for
fairly short strings.
This patch adds a new style strategy flag to disable shaping and
will just uses the CMAP and HDMX tables to get glyph indices and advances
for the characters. In Qt 6, the TextBypassShaping flag can be removed
completely and be replaced by the style strategy.
[ChangeLog][QtGui][Text] Added QFont::PreferNoShaping style strategy to support
improvements to performance at the expense of some cosmetic font features.
Task-number: QTBUG-56728
Change-Id: I48e025dcc06afe02824bf5b5011702a7e0036f6d
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/gui/text/qtextengine.cpp')
-rw-r--r-- | src/gui/text/qtextengine.cpp | 85 |
1 files changed, 56 insertions, 29 deletions
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; |