Fix character mirroring issue with HarfBuzz-NG

HarfBuzz-NG does character mirroring where appropriate.
A simple solution is to unset RightToLeft shaper flag when
text gets shaped with HB-NG. Instead, move the mirroring code
right to HB-old proxy function and decrease code duplication.

Change-Id: Icdcd50b73b3e6a43da4b85addc7d8f51edf86512
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
This commit is contained in:
Konstantin Ritt 2014-02-03 20:38:20 +02:00 committed by The Qt Project
parent 2edf3ba5a7
commit 19463c5c3f
8 changed files with 44 additions and 63 deletions

View File

@ -89,18 +89,48 @@ static HB_Bool hb_stringToGlyphs(HB_Font font, const HB_UChar16 *string, hb_uint
{
QFontEngine *fe = (QFontEngine *)font->userData;
const QChar *str = reinterpret_cast<const QChar *>(string);
QGlyphLayout qglyphs;
qglyphs.numGlyphs = *numGlyphs;
qglyphs.glyphs = glyphs;
QFontEngine::ShaperFlags shaperFlags(QFontEngine::GlyphIndicesOnly);
if (rightToLeft)
shaperFlags |= QFontEngine::RightToLeft;
int nGlyphs = *numGlyphs;
bool result = fe->stringToCMap(reinterpret_cast<const QChar *>(string), length, &qglyphs, &nGlyphs, shaperFlags);
bool result = fe->stringToCMap(str, length, &qglyphs, &nGlyphs, QFontEngine::GlyphIndicesOnly);
*numGlyphs = nGlyphs;
if (rightToLeft && result && !fe->symbol) {
uint glyph_pos = 0;
for (uint i = 0; i < length; ++i, ++glyph_pos) {
uint ucs4 = str[i].unicode();
if (Q_UNLIKELY(QChar::isHighSurrogate(ucs4) && i + 1 < length)) {
uint low = str[i + 1].unicode();
if (Q_LIKELY(QChar::isLowSurrogate(low))) {
ucs4 = QChar::surrogateToUcs4(ucs4, low);
++i;
}
}
uint mirrored = QChar::mirroredChar(ucs4);
if (Q_UNLIKELY(mirrored != ucs4)) {
QChar chars[2];
uint numChars = 0;
if (Q_UNLIKELY(QChar::requiresSurrogates(mirrored))) {
chars[numChars++] = QChar(QChar::highSurrogate(mirrored));
chars[numChars++] = QChar(QChar::lowSurrogate(mirrored));
} else {
chars[numChars++] = QChar(mirrored);
}
qglyphs.numGlyphs = numChars;
qglyphs.glyphs = glyphs + glyph_pos;
nGlyphs = numChars;
if (!fe->stringToCMap(chars, numChars, &qglyphs, &nGlyphs, QFontEngine::GlyphIndicesOnly))
Q_UNREACHABLE();
Q_ASSERT(nGlyphs == 1);
}
}
}
return result;
}

View File

@ -1516,7 +1516,6 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs
return false;
}
bool mirrored = flags & QFontEngine::RightToLeft;
int glyph_pos = 0;
if (freetype->symbol_map) {
FT_Face face = freetype->face;
@ -1552,8 +1551,6 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs
FT_Face face = freetype->face;
for (int i = 0; i < len; ++i) {
unsigned int uc = getChar(str, i, len);
if (mirrored)
uc = QChar::mirroredChar(uc);
glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
if (!glyphs->glyphs[glyph_pos]) {
{

View File

@ -120,7 +120,6 @@ public:
};
enum ShaperFlag {
RightToLeft = 0x0001,
DesignMetrics = 0x0002,
GlyphIndicesOnly = 0x0004
};

View File

@ -353,13 +353,10 @@ bool QFontEngineQPA::stringToCMap(const QChar *str, int len, QGlyphLayout *glyph
const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset);
bool mirrored = flags & QFontEngine::RightToLeft;
int glyph_pos = 0;
if (symbol) {
for (int i = 0; i < len; ++i) {
unsigned int uc = getChar(str, i, len);
if (mirrored)
uc = QChar::mirroredChar(uc);
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
@ -368,8 +365,6 @@ bool QFontEngineQPA::stringToCMap(const QChar *str, int len, QGlyphLayout *glyph
} else {
for (int i = 0; i < len; ++i) {
unsigned int uc = getChar(str, i, len);
if (mirrored)
uc = QChar::mirroredChar(uc);
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
#if 0 && defined(DEBUG_FONTENGINE)
QChar c(uc);

View File

@ -932,9 +932,6 @@ void QTextEngine::shapeText(int item) const
int nGlyphs = initialGlyphs.numGlyphs;
QFontEngine::ShaperFlags shaperFlags(QFontEngine::GlyphIndicesOnly);
if (si.analysis.bidiLevel % 2)
shaperFlags |= QFontEngine::RightToLeft;
if (!fontEngine->stringToCMap(reinterpret_cast<const QChar *>(string), itemLength, &initialGlyphs, &nGlyphs, shaperFlags)) {
nGlyphs = qMax(nGlyphs, itemLength); // ### needed for QFontEngine::stringToCMap() to not fail twice
if (!ensureSpace(nGlyphs)) {
@ -1274,7 +1271,8 @@ int QTextEngine::shapeTextWithHarfbuzz(const QScriptItem &si, const ushort *stri
engineIdx = uint(availableGlyphs(&si).glyphs[glyph_pos] >> 24);
actualFontEngine = static_cast<QFontEngineMulti *>(fontEngine)->engine(engineIdx);
shaper_item.glyphIndicesPresent = true;
if ((si.analysis.bidiLevel % 2) == 0)
shaper_item.glyphIndicesPresent = true;
}
shaper_item.font = (HB_Font)actualFontEngine->harfbuzzFont();

View File

@ -219,44 +219,11 @@ inline unsigned int getChar(const QChar *str, int &i, const int len)
return uc;
}
int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs, bool mirrored) const
int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs) const
{
int i = 0;
int glyph_pos = 0;
if (mirrored) {
#if defined(Q_OS_WINCE)
{
#else
if (symbol) {
for (; i < numChars; ++i, ++glyph_pos) {
unsigned int uc = getChar(str, i, numChars);
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
if (!glyphs->glyphs[glyph_pos] && uc < 0x100)
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
}
} else if (ttf) {
for (; i < numChars; ++i, ++glyph_pos) {
unsigned int uc = getChar(str, i, numChars);
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, QChar::mirroredChar(uc));
}
} else {
#endif
wchar_t first = tm.tmFirstChar;
wchar_t last = tm.tmLastChar;
for (; i < numChars; ++i, ++glyph_pos) {
uint ucs = QChar::mirroredChar(getChar(str, i, numChars));
if (
#ifdef Q_WS_WINCE
tm.tmFirstChar > 60000 ||
#endif
ucs >= first && ucs <= last)
glyphs->glyphs[glyph_pos] = ucs;
else
glyphs->glyphs[glyph_pos] = 0;
}
}
} else {
{
#if defined(Q_OS_WINCE)
{
#else
@ -390,7 +357,7 @@ bool QWindowsFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *g
}
glyphs->numGlyphs = *nglyphs;
*nglyphs = getGlyphIndexes(str, len, glyphs, flags & RightToLeft);
*nglyphs = getGlyphIndexes(str, len, glyphs);
if (!(flags & GlyphIndicesOnly))
recalcAdvances(glyphs, flags);

View File

@ -127,7 +127,7 @@ public:
virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing = 0, qreal *rightBearing = 0);
#endif
int getGlyphIndexes(const QChar *ch, int numChars, QGlyphLayout *glyphs, bool mirrored) const;
int getGlyphIndexes(const QChar *ch, int numChars, QGlyphLayout *glyphs) const;
void getCMap();
bool getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const;

View File

@ -325,13 +325,8 @@ bool QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGly
QVarLengthArray<UINT32> codePoints(len);
int actualLength = 0;
if (flags & QFontEngine::RightToLeft) {
for (int i = 0; i < len; ++i)
codePoints[actualLength++] = QChar::mirroredChar(getChar(str, i, len));
} else {
for (int i = 0; i < len; ++i)
codePoints[actualLength++] = getChar(str, i, len);
}
for (int i = 0; i < len; ++i)
codePoints[actualLength++] = getChar(str, i, len);
QVarLengthArray<UINT16> glyphIndices(actualLength);
HRESULT hr = m_directWriteFontFace->GetGlyphIndicesW(codePoints.data(), actualLength,