diff options
-rw-r--r-- | src/gui/text/coretext/qfontengine_coretext.mm | 30 | ||||
-rw-r--r-- | src/gui/text/coretext/qfontengine_coretext_p.h | 2 | ||||
-rw-r--r-- | src/gui/text/freetype/qfontengine_ft.cpp | 11 | ||||
-rw-r--r-- | src/gui/text/freetype/qfontengine_ft_p.h | 2 | ||||
-rw-r--r-- | src/gui/text/qfont.cpp | 10 | ||||
-rw-r--r-- | src/gui/text/qfont.h | 1 | ||||
-rw-r--r-- | src/gui/text/qfontengine.cpp | 79 | ||||
-rw-r--r-- | src/gui/text/qfontengine_p.h | 17 | ||||
-rw-r--r-- | src/gui/text/qrawfont.cpp | 4 | ||||
-rw-r--r-- | src/gui/text/qtextengine.cpp | 17 | ||||
-rw-r--r-- | src/gui/text/qtextengine_p.h | 1 | ||||
-rw-r--r-- | src/gui/text/windows/qwindowsfontengine.cpp | 16 | ||||
-rw-r--r-- | src/gui/text/windows/qwindowsfontengine_p.h | 4 | ||||
-rw-r--r-- | src/gui/text/windows/qwindowsfontenginedirectwrite.cpp | 16 | ||||
-rw-r--r-- | src/gui/text/windows/qwindowsfontenginedirectwrite_p.h | 4 | ||||
-rw-r--r-- | tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.cpp | 4 |
16 files changed, 152 insertions, 66 deletions
diff --git a/src/gui/text/coretext/qfontengine_coretext.mm b/src/gui/text/coretext/qfontengine_coretext.mm index b6fef2fecb..1050c03d75 100644 --- a/src/gui/text/coretext/qfontengine_coretext.mm +++ b/src/gui/text/coretext/qfontengine_coretext.mm @@ -13,6 +13,7 @@ #include <private/qcoregraphics_p.h> #include <private/qimage_p.h> #include <private/qguiapplication_p.h> +#include <private/qstringiterator_p.h> #include <qpa/qplatformtheme.h> #include <cmath> @@ -274,29 +275,30 @@ glyph_t QCoreTextFontEngine::glyphIndex(uint ucs4) const return glyphIndices[0]; } -bool QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, - int *nglyphs, QFontEngine::ShaperFlags flags) const +int QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, + int *nglyphs, QFontEngine::ShaperFlags flags) const { Q_ASSERT(glyphs->numGlyphs >= *nglyphs); if (*nglyphs < len) { *nglyphs = len; - return false; + return -1; } QVarLengthArray<CGGlyph> cgGlyphs(len); CTFontGetGlyphsForCharacters(ctfont, (const UniChar*)str, cgGlyphs.data(), len); int glyph_pos = 0; - for (int i = 0; i < len; ++i) { - glyphs->glyphs[glyph_pos] = cgGlyphs[i]; - if (glyph_pos < i) - cgGlyphs[glyph_pos] = cgGlyphs[i]; - glyph_pos++; - - // If it's a non-BMP char, skip the lower part of surrogate pair and go - // directly to the next char without increasing glyph_pos - if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) - ++i; + int mappedGlyphs = 0; + QStringIterator it(str, str + len); + while (it.hasNext()) { + qsizetype idx = it.index(); + char32_t ucs4 = it.next(); + glyphs->glyphs[glyph_pos] = cgGlyphs[idx]; + if (glyph_pos < idx) + cgGlyphs[glyph_pos] = cgGlyphs[idx]; + if (glyphs->glyphs[glyph_pos] != 0 || isIgnorableChar(ucs4)) + mappedGlyphs++; + glyph_pos++; } *nglyphs = glyph_pos; @@ -305,7 +307,7 @@ bool QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout * if (!(flags & GlyphIndicesOnly)) loadAdvancesForGlyphs(cgGlyphs, glyphs); - return true; + return mappedGlyphs; } glyph_metrics_t QCoreTextFontEngine::boundingBox(glyph_t glyph) diff --git a/src/gui/text/coretext/qfontengine_coretext_p.h b/src/gui/text/coretext/qfontengine_coretext_p.h index af87f5f6f3..2f388c32bc 100644 --- a/src/gui/text/coretext/qfontengine_coretext_p.h +++ b/src/gui/text/coretext/qfontengine_coretext_p.h @@ -38,7 +38,7 @@ public: ~QCoreTextFontEngine(); glyph_t glyphIndex(uint ucs4) const override; - bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override; + int stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override; void recalcAdvances(QGlyphLayout *, ShaperFlags) const override; glyph_metrics_t boundingBox(glyph_t glyph) override; diff --git a/src/gui/text/freetype/qfontengine_ft.cpp b/src/gui/text/freetype/qfontengine_ft.cpp index 72d2c72fe3..d3791f1f6e 100644 --- a/src/gui/text/freetype/qfontengine_ft.cpp +++ b/src/gui/text/freetype/qfontengine_ft.cpp @@ -1678,15 +1678,16 @@ glyph_t QFontEngineFT::glyphIndex(uint ucs4) const return glyph; } -bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, +int QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const { Q_ASSERT(glyphs->numGlyphs >= *nglyphs); if (*nglyphs < len) { *nglyphs = len; - return false; + return -1; } + int mappedGlyphs = 0; int glyph_pos = 0; if (freetype->symbol_map) { FT_Face face = freetype->face; @@ -1719,6 +1720,8 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs if (uc < QFreetypeFace::cmapCacheSize) freetype->cmapCache[uc] = glyph; } + if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc)) + mappedGlyphs++; ++glyph_pos; } } else { @@ -1740,6 +1743,8 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs freetype->cmapCache[uc] = glyph; } } + if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc)) + mappedGlyphs++; ++glyph_pos; } } @@ -1750,7 +1755,7 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs if (!(flags & GlyphIndicesOnly)) recalcAdvances(glyphs, flags); - return true; + return mappedGlyphs; } bool QFontEngineFT::shouldUseDesignMetrics(QFontEngine::ShaperFlags flags) const diff --git a/src/gui/text/freetype/qfontengine_ft_p.h b/src/gui/text/freetype/qfontengine_ft_p.h index c8e5e20d37..bdd4549827 100644 --- a/src/gui/text/freetype/qfontengine_ft_p.h +++ b/src/gui/text/freetype/qfontengine_ft_p.h @@ -186,7 +186,7 @@ private: void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags) override; - bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override; + int stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override; glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override; glyph_metrics_t boundingBox(glyph_t glyph) override; diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index 7fd590c355..f3b861957e 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -1462,6 +1462,14 @@ QFont::StyleHint QFont::styleHint() const \value NoAntialias don't antialias the fonts. \value NoSubpixelAntialias avoid subpixel antialiasing on the fonts if possible. \value PreferAntialias antialias if possible. + \value [since 6.8] ContextFontMerging If the selected font does not contain a certain character, + then Qt automatically chooses a similar-looking fallback font that contains the + character. By default this is done on a character-by-character basis. This means that in + certain uncommon cases, multiple fonts may be used to represent one string of text even + if it's in the same script. Setting \c ContextFontMerging will try finding the fallback + font that matches the largest subset of the input string instead. This will be more + expensive for strings where missing glyphs occur, but may give more consistent results. + If \c NoFontMerging is set, then \c ContextFontMerging will have no effect. \value NoFontMerging If the font selected for a certain writing system does not contain a character requested to draw, then Qt automatically chooses a similar looking font that contains the character. The NoFontMerging flag disables this feature. @@ -3266,7 +3274,7 @@ bool QFontInfo::fixedPitch() const QChar ch[2] = { u'i', u'm' }; QGlyphLayoutArray<2> g; int l = 2; - if (!engine->stringToCMap(ch, 2, &g, &l, {})) + if (engine->stringToCMap(ch, 2, &g, &l, {}) < 0) Q_UNREACHABLE(); Q_ASSERT(l == 2); engine->fontDef.fixedPitch = g.advances[0] == g.advances[1]; diff --git a/src/gui/text/qfont.h b/src/gui/text/qfont.h index ace07780b5..66a5f7c155 100644 --- a/src/gui/text/qfont.h +++ b/src/gui/text/qfont.h @@ -47,6 +47,7 @@ public: NoAntialias = 0x0100, NoSubpixelAntialias = 0x0800, PreferNoShaping = 0x1000, + ContextFontMerging = 0x2000, NoFontMerging = 0x8000 }; Q_ENUM(StyleStrategy) diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index dff400c18b..4e78aaac2e 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -13,6 +13,7 @@ #include "qpainter.h" #include "qpainterpath.h" #include "qvarlengtharray.h" +#include "qtextengine_p.h" #include <qmath.h> #include <qendian.h> #include <private/qstringiterator_p.h> @@ -1542,12 +1543,12 @@ glyph_t QFontEngineBox::glyphIndex(uint ucs4) const return 1; } -bool QFontEngineBox::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const +int QFontEngineBox::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const { Q_ASSERT(glyphs->numGlyphs >= *nglyphs); if (*nglyphs < len) { *nglyphs = len; - return false; + return -1; } int ucs4Length = 0; @@ -1563,7 +1564,7 @@ bool QFontEngineBox::stringToCMap(const QChar *str, int len, QGlyphLayout *glyph if (!(flags & GlyphIndicesOnly)) recalcAdvances(glyphs, flags); - return true; + return *nglyphs; } void QFontEngineBox::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const @@ -1793,11 +1794,7 @@ QFontEngine *QFontEngineMulti::loadEngine(int at) glyph_t QFontEngineMulti::glyphIndex(uint ucs4) const { glyph_t glyph = engine(0)->glyphIndex(ucs4); - if (glyph == 0 - && ucs4 != QChar::LineSeparator - && ucs4 != QChar::LineFeed - && ucs4 != QChar::CarriageReturn - && ucs4 != QChar::ParagraphSeparator) { + if (glyph == 0 && !isIgnorableChar(ucs4)) { if (!m_fallbackFamiliesQueried) const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried(); for (int x = 1, n = qMin(m_engines.size(), 256); x < n; ++x) { @@ -1824,13 +1821,55 @@ glyph_t QFontEngineMulti::glyphIndex(uint ucs4) const return glyph; } -bool QFontEngineMulti::stringToCMap(const QChar *str, int len, - QGlyphLayout *glyphs, int *nglyphs, - QFontEngine::ShaperFlags flags) const +int QFontEngineMulti::stringToCMap(const QChar *str, int len, + QGlyphLayout *glyphs, int *nglyphs, + QFontEngine::ShaperFlags flags) const { - if (!engine(0)->stringToCMap(str, len, glyphs, nglyphs, flags)) - return false; + const int originalNumGlyphs = glyphs->numGlyphs; + int mappedGlyphCount = engine(0)->stringToCMap(str, len, glyphs, nglyphs, flags); + if (mappedGlyphCount < 0) + return -1; + + // If ContextFontMerging is set and the match for the string was incomplete, we try all + // fallbacks on the full string until we find the best match. + bool contextFontMerging = mappedGlyphCount < *nglyphs && (fontDef.styleStrategy & QFont::ContextFontMerging); + if (contextFontMerging) { + QVarLengthGlyphLayoutArray tempLayout(len); + if (!m_fallbackFamiliesQueried) + const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried(); + int maxGlyphCount = 0; + uchar engineIndex = 0; + for (int x = 1, n = qMin(m_engines.size(), 256); x < n; ++x) { + int numGlyphs = len; + const_cast<QFontEngineMulti *>(this)->ensureEngineAt(x); + maxGlyphCount = engine(x)->stringToCMap(str, len, &tempLayout, &numGlyphs, flags); + + // If we found a better match, we copy data into the main QGlyphLayout + if (maxGlyphCount > mappedGlyphCount) { + *nglyphs = numGlyphs; + glyphs->numGlyphs = originalNumGlyphs; + glyphs->copy(&tempLayout); + engineIndex = x; + if (maxGlyphCount == numGlyphs) + break; + } + } + + if (engineIndex > 0) { + for (int y = 0; y < glyphs->numGlyphs; ++y) { + if (glyphs->glyphs[y] != 0) + glyphs->glyphs[y] |= (engineIndex << 24); + } + } else { + contextFontMerging = false; + } + + mappedGlyphCount = maxGlyphCount; + } + + // Fill in missing glyphs by going through string one character at the time and finding + // the first viable fallback. int glyph_pos = 0; QStringIterator it(str, str + len); @@ -1861,15 +1900,10 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len, lastFallback = -1; } - if (glyphs->glyphs[glyph_pos] == 0 - && ucs4 != QChar::LineSeparator - && ucs4 != QChar::LineFeed - && ucs4 != QChar::CarriageReturn - && ucs4 != QChar::ParagraphSeparator - && QChar::category(ucs4) != QChar::Other_Control) { + if (glyphs->glyphs[glyph_pos] == 0 && !isIgnorableChar(ucs4)) { if (!m_fallbackFamiliesQueried) const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried(); - for (int x = 1, n = qMin(m_engines.size(), 256); x < n; ++x) { + for (int x = contextFontMerging ? 0 : 1, n = qMin(m_engines.size(), 256); x < n; ++x) { QFontEngine *engine = m_engines.at(x); if (!engine) { if (!shouldLoadFontEngineForCharacter(x, ucs4)) @@ -1946,8 +1980,7 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len, *nglyphs = glyph_pos; glyphs->numGlyphs = glyph_pos; - - return true; + return mappedGlyphCount; } bool QFontEngineMulti::shouldLoadFontEngineForCharacter(int at, uint ucs4) const @@ -2239,7 +2272,7 @@ bool QFontEngineMulti::canRender(const QChar *string, int len) const QGlyphLayout g; g.numGlyphs = nglyphs; g.glyphs = glyphs.data(); - if (!stringToCMap(string, len, &g, &nglyphs, GlyphIndicesOnly)) + if (stringToCMap(string, len, &g, &nglyphs, GlyphIndicesOnly) < 0) Q_UNREACHABLE(); for (int i = 0; i < nglyphs; i++) { diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index af44eeab3f..a0e0801354 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -76,7 +76,8 @@ public: enum ShaperFlag { DesignMetrics = 0x0002, - GlyphIndicesOnly = 0x0004 + GlyphIndicesOnly = 0x0004, + FullStringFallback = 0x008 }; Q_DECLARE_FLAGS(ShaperFlags, ShaperFlag) @@ -148,12 +149,20 @@ public: } bool isColorFont() const { return glyphFormat == Format_ARGB; } + static bool isIgnorableChar(char32_t ucs4) + { + return ucs4 == QChar::LineSeparator + || ucs4 == QChar::LineFeed + || ucs4 == QChar::CarriageReturn + || ucs4 == QChar::ParagraphSeparator + || QChar::category(ucs4) == QChar::Other_Control; + } virtual QFixed emSquareSize() const { return ascent(); } /* returns 0 as glyph index for non existent glyphs */ virtual glyph_t glyphIndex(uint ucs4) const = 0; - virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const = 0; + virtual int stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const = 0; virtual void recalcAdvances(QGlyphLayout *, ShaperFlags) const {} virtual void doKerning(QGlyphLayout *, ShaperFlags) const; @@ -393,7 +402,7 @@ public: ~QFontEngineBox(); virtual glyph_t glyphIndex(uint ucs4) const override; - virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override; + virtual int stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override; virtual void recalcAdvances(QGlyphLayout *, ShaperFlags) const override; void draw(QPaintEngine *p, qreal x, qreal y, const QTextItemInt &si); @@ -431,7 +440,7 @@ public: ~QFontEngineMulti(); virtual glyph_t glyphIndex(uint ucs4) const override; - virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override; + virtual int stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override; virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override; virtual glyph_metrics_t boundingBox(glyph_t glyph) override; diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp index c5a92f95cb..54676b3560 100644 --- a/src/gui/text/qrawfont.cpp +++ b/src/gui/text/qrawfont.cpp @@ -498,7 +498,7 @@ QList<quint32> QRawFont::glyphIndexesForString(const QString &text) const QGlyphLayout glyphs; glyphs.numGlyphs = numGlyphs; glyphs.glyphs = glyphIndexes.data(); - if (!d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly)) + if (d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly) < 0) Q_UNREACHABLE(); glyphIndexes.resize(numGlyphs); @@ -531,7 +531,7 @@ bool QRawFont::glyphIndexesForChars(const QChar *chars, int numChars, quint32 *g QGlyphLayout glyphs; glyphs.numGlyphs = *numGlyphs; glyphs.glyphs = glyphIndexes; - return d->fontEngine->stringToCMap(chars, numChars, &glyphs, numGlyphs, QFontEngine::GlyphIndicesOnly); + return d->fontEngine->stringToCMap(chars, numChars, &glyphs, numGlyphs, QFontEngine::GlyphIndicesOnly) >= 0; } /*! diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index cb945b73ce..a18157ab9b 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -1445,7 +1445,7 @@ void QTextEngine::shapeText(int item) const shapingEnabled ? QFontEngine::GlyphIndicesOnly : QFontEngine::ShaperFlag(0); - if (!fontEngine->stringToCMap(reinterpret_cast<const QChar *>(string), itemLength, &initialGlyphs, &nGlyphs, shaperFlags)) + if (fontEngine->stringToCMap(reinterpret_cast<const QChar *>(string), itemLength, &initialGlyphs, &nGlyphs, shaperFlags) < 0) Q_UNREACHABLE(); } @@ -2741,6 +2741,21 @@ bool QTextEngine::LayoutData::reallocate(int totalGlyphs) return true; } +void QGlyphLayout::copy(QGlyphLayout *oldLayout) +{ + Q_ASSERT(offsets != oldLayout->offsets); + + int n = std::min(numGlyphs, oldLayout->numGlyphs); + + memcpy(offsets, oldLayout->offsets, n * sizeof(QFixedPoint)); + memcpy(attributes, oldLayout->attributes, n * sizeof(QGlyphAttributes)); + memcpy(justifications, oldLayout->justifications, n * sizeof(QGlyphJustification)); + memcpy(advances, oldLayout->advances, n * sizeof(QFixed)); + memcpy(glyphs, oldLayout->glyphs, n * sizeof(glyph_t)); + + numGlyphs = n; +} + // grow to the new size, copying the existing data to the new layout void QGlyphLayout::grow(char *address, int totalGlyphs) { diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index a829265a22..c01d3a0711 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -224,6 +224,7 @@ struct QGlyphLayout return reinterpret_cast<char *>(offsets); } + void copy(QGlyphLayout *other); void grow(char *address, int totalGlyphs); }; diff --git a/src/gui/text/windows/qwindowsfontengine.cpp b/src/gui/text/windows/qwindowsfontengine.cpp index fe07897369..5de80dc8a3 100644 --- a/src/gui/text/windows/qwindowsfontengine.cpp +++ b/src/gui/text/windows/qwindowsfontengine.cpp @@ -132,8 +132,9 @@ void QWindowsFontEngine::getCMap() } } -int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs) const +int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs, int *mappedGlyphs) const { + *mappedGlyphs = 0; int glyph_pos = 0; { if (symbol) { @@ -143,6 +144,8 @@ int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLa glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc); if (!glyphs->glyphs[glyph_pos] && uc < 0x100) glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc + 0xf000); + if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc)) + (*mappedGlyphs)++; ++glyph_pos; } } else if (ttf) { @@ -150,6 +153,8 @@ int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLa while (it.hasNext()) { const uint uc = it.next(); glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc); + if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc)) + (*mappedGlyphs)++; ++glyph_pos; } } else { @@ -160,6 +165,8 @@ int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLa glyphs->glyphs[glyph_pos] = uc; else glyphs->glyphs[glyph_pos] = 0; + if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc)) + (*mappedGlyphs)++; ++glyph_pos; } } @@ -259,7 +266,7 @@ HGDIOBJ QWindowsFontEngine::selectDesignFont() const return SelectObject(m_fontEngineData->hdc, designFont); } -bool QWindowsFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const +int QWindowsFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const { Q_ASSERT(glyphs->numGlyphs >= *nglyphs); if (*nglyphs < len) { @@ -268,12 +275,13 @@ bool QWindowsFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *g } glyphs->numGlyphs = *nglyphs; - *nglyphs = getGlyphIndexes(str, len, glyphs); + int mappedGlyphs; + *nglyphs = getGlyphIndexes(str, len, glyphs, &mappedGlyphs); if (!(flags & GlyphIndicesOnly)) recalcAdvances(glyphs, flags); - return true; + return mappedGlyphs; } inline void calculateTTFGlyphWidth(HDC hdc, UINT glyph, int &width) diff --git a/src/gui/text/windows/qwindowsfontengine_p.h b/src/gui/text/windows/qwindowsfontengine_p.h index afe8ee4ca5..07f4db3c4a 100644 --- a/src/gui/text/windows/qwindowsfontengine_p.h +++ b/src/gui/text/windows/qwindowsfontengine_p.h @@ -48,7 +48,7 @@ public: QFixed emSquareSize() const override; glyph_t glyphIndex(uint ucs4) const override; - bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override; + int stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override; void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags) const override; void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags) override; @@ -88,7 +88,7 @@ public: bool hasUnreliableGlyphOutline() const override; - int getGlyphIndexes(const QChar *ch, int numChars, QGlyphLayout *glyphs) const; + int getGlyphIndexes(const QChar *ch, int numChars, QGlyphLayout *glyphs, int *mappedGlyphs) const; void getCMap(); bool getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const; diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp index 2070deb296..47b8a7ee3c 100644 --- a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp +++ b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp @@ -435,13 +435,13 @@ glyph_t QWindowsFontEngineDirectWrite::glyphIndex(uint ucs4) const return glyphIndex; } -bool QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, - int *nglyphs, QFontEngine::ShaperFlags flags) const +int QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, + int *nglyphs, QFontEngine::ShaperFlags flags) const { Q_ASSERT(glyphs->numGlyphs >= *nglyphs); if (*nglyphs < len) { *nglyphs = len; - return false; + return -1; } QVarLengthArray<UINT32> codePoints(len); @@ -455,11 +455,15 @@ bool QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGly glyphIndices.data()); if (FAILED(hr)) { qErrnoWarning("%s: GetGlyphIndicesW failed", __FUNCTION__); - return false; + return -1; } - for (int i = 0; i < actualLength; ++i) + int mappedGlyphs = 0; + for (int i = 0; i < actualLength; ++i) { glyphs->glyphs[i] = glyphIndices.at(i); + if (glyphs->glyphs[i] != 0 || isIgnorableChar(codePoints.at(i))) + mappedGlyphs++; + } *nglyphs = actualLength; glyphs->numGlyphs = actualLength; @@ -467,7 +471,7 @@ bool QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGly if (!(flags & GlyphIndicesOnly)) recalcAdvances(glyphs, {}); - return true; + return mappedGlyphs; } QFontEngine::FaceId QWindowsFontEngineDirectWrite::faceId() const diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h b/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h index 44e466789c..d7c9a79267 100644 --- a/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h +++ b/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h @@ -53,8 +53,8 @@ public: QFixed emSquareSize() const override; glyph_t glyphIndex(uint ucs4) const override; - bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, - ShaperFlags flags) const override; + int stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, + ShaperFlags flags) const override; void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags) const override; void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, diff --git a/tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.cpp b/tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.cpp index 678eb0393f..9471c1d93f 100644 --- a/tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.cpp +++ b/tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.cpp @@ -263,7 +263,7 @@ void tst_QFontMetrics::inFontUcs4() glyphs.glyphs[0] = 0; QVERIFY(engine->stringToCMap(string.constData(), string.size(), &glyphs, &glyphs.numGlyphs, - QFontEngine::GlyphIndicesOnly)); + QFontEngine::GlyphIndicesOnly) > 0); QCOMPARE(glyphs.numGlyphs, 1); QCOMPARE(glyphs.glyphs[0], uint(1)); } @@ -275,7 +275,7 @@ void tst_QFontMetrics::inFontUcs4() glyphs.glyphs[0] = 0; QVERIFY(engine->stringToCMap(string.constData(), string.size(), &glyphs, &glyphs.numGlyphs, - QFontEngine::GlyphIndicesOnly)); + QFontEngine::GlyphIndicesOnly) >= 0); QVERIFY(glyphs.glyphs[0] != 1); } } |