Optimize glyph lookups with QFontEngine::glyphIndex(uint)

Change-Id: I56c7e727f3d9b08195f38939106620c744c6eaf0
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Reviewed-by: BogDan Vatra <bogdan@kde.org>
bb10
Konstantin Ritt 2014-03-05 07:02:12 +02:00 committed by The Qt Project
parent f99fd06d7d
commit f697f3ceb6
8 changed files with 61 additions and 263 deletions

View File

@ -739,20 +739,11 @@ bool qt_fontHasNarrowOutlines(QFontEngine *fontEngine)
if (!fe)
return false;
const QChar uc(QLatin1Char('O'));
QImage im;
glyph_t glyph;
QGlyphLayout glyphs;
glyphs.numGlyphs = 1;
glyphs.glyphs = &glyph;
int numGlyphs = 1;
if (!fe->stringToCMap(&uc, 1, &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly))
Q_UNREACHABLE();
Q_ASSERT(numGlyphs == 1);
QImage im = fe->alphaMapForGlyph(glyph, QFixed(), QTransform());
const glyph_t glyph = fe->glyphIndex('O');
if (glyph != 0)
im = fe->alphaMapForGlyph(glyph, QFixed(), QTransform());
Q_ASSERT(fe->ref.load() == 0);
delete fe;

View File

@ -101,35 +101,13 @@ static HB_Bool hb_stringToGlyphs(HB_Font font, const HB_UChar16 *string, hb_uint
*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);
}
QStringIterator it(str, str + length);
while (it.hasNext()) {
const uint ucs4 = it.next();
const uint mirrored = QChar::mirroredChar(ucs4);
if (Q_UNLIKELY(mirrored != ucs4))
*glyphs = fe->glyphIndex(mirrored);
++glyphs;
}
}
@ -417,38 +395,14 @@ glyph_metrics_t QFontEngine::boundingBox(glyph_t glyph, const QTransform &matrix
QFixed QFontEngine::xHeight() const
{
QChar x((ushort)'x');
glyph_t glyph;
QGlyphLayout glyphs;
glyphs.numGlyphs = 1;
glyphs.glyphs = &glyph;
int nglyphs = 1;
if (!stringToCMap(&x, 1, &glyphs, &nglyphs, GlyphIndicesOnly))
Q_UNREACHABLE();
Q_ASSERT(nglyphs == 1);
const glyph_t glyph = glyphIndex('x');
glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyph);
return bb.height;
}
QFixed QFontEngine::averageCharWidth() const
{
QChar x((ushort)'x');
glyph_t glyph;
QGlyphLayout glyphs;
glyphs.numGlyphs = 1;
glyphs.glyphs = &glyph;
int nglyphs = 1;
if (!stringToCMap(&x, 1, &glyphs, &nglyphs, GlyphIndicesOnly))
Q_UNREACHABLE();
Q_ASSERT(nglyphs == 1);
const glyph_t glyph = glyphIndex('x');
glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyph);
return bb.xoff;
}
@ -509,18 +463,14 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform
if (glyphs.justifications[i].nKashidas) {
QChar ch(0x640); // Kashida character
glyph_t kashidaGlyph;
glyph_t kashidaGlyph = glyphIndex(ch.unicode());
QFixed kashidaWidth;
QGlyphLayout g;
g.numGlyphs = 1;
g.glyphs = &kashidaGlyph;
g.advances = &kashidaWidth;
int nglyphs = 1;
if (!stringToCMap(&ch, 1, &g, &nglyphs, 0))
Q_UNREACHABLE();
Q_ASSERT(nglyphs == 1);
recalcAdvances(&g, 0);
for (uint k = 0; k < glyphs.justifications[i].nKashidas; ++k) {
xpos -= kashidaWidth;

View File

@ -1282,22 +1282,10 @@ qreal QFontEngineFT::minRightBearing() const
{
if (rbearing == SHRT_MIN) {
lbearing = rbearing = 0;
const QChar *ch = reinterpret_cast<const QChar *>(char_table);
glyph_t glyphs[char_table_entries];
QGlyphLayout g;
g.glyphs = glyphs;
g.numGlyphs = char_table_entries;
int ng = char_table_entries;
if (!stringToCMap(ch, char_table_entries, &g, &ng, GlyphIndicesOnly))
Q_UNREACHABLE();
Q_ASSERT(ng == char_table_entries);
while (--ng) {
if (glyphs[ng]) {
glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs[ng]);
for (int i = 0; i < char_table_entries; ++i) {
const glyph_t glyph = glyphIndex(char_table[i]);
if (glyph != 0) {
glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyph);
lbearing = qMin(lbearing, gi.x);
rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
}

View File

@ -410,12 +410,7 @@ int QFontMetrics::averageCharWidth() const
*/
bool QFontMetrics::inFont(QChar ch) const
{
const int script = ch.script();
QFontEngine *engine = d->engineForScript(script);
Q_ASSERT(engine != 0);
if (engine->type() == QFontEngine::Box)
return false;
return engine->canRender(&ch, 1);
return inFontUcs4(ch.unicode());
}
/*!
@ -458,16 +453,7 @@ int QFontMetrics::leftBearing(QChar ch) const
d->alterCharForCapitalization(ch);
glyph_t glyph;
QGlyphLayout glyphs;
glyphs.numGlyphs = 1;
glyphs.glyphs = &glyph;
int nglyphs = 1;
if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly))
Q_UNREACHABLE();
Q_ASSERT(nglyphs == 1);
glyph_t glyph = engine->glyphIndex(ch.unicode());
qreal lb;
engine->getGlyphBearings(glyph, &lb);
@ -500,16 +486,7 @@ int QFontMetrics::rightBearing(QChar ch) const
d->alterCharForCapitalization(ch);
glyph_t glyph;
QGlyphLayout glyphs;
glyphs.numGlyphs = 1;
glyphs.glyphs = &glyph;
int nglyphs = 1;
if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly))
Q_UNREACHABLE();
Q_ASSERT(nglyphs == 1);
glyph_t glyph = engine->glyphIndex(ch.unicode());
qreal rb;
engine->getGlyphBearings(glyph, 0, &rb);
@ -605,18 +582,14 @@ int QFontMetrics::width(QChar ch) const
d->alterCharForCapitalization(ch);
glyph_t glyph = engine->glyphIndex(ch.unicode());
QFixed advance;
QGlyphLayout glyphs;
glyphs.numGlyphs = 1;
glyph_t glyph;
glyphs.glyphs = &glyph;
glyphs.advances = &advance;
int nglyphs = 1;
if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0))
Q_UNREACHABLE();
Q_ASSERT(nglyphs == 1);
engine->recalcAdvances(&glyphs, 0);
return qRound(advance);
}
@ -660,18 +633,14 @@ int QFontMetrics::charWidth(const QString &text, int pos) const
d->alterCharForCapitalization(ch);
glyph_t glyph = engine->glyphIndex(ch.unicode());
QFixed advance;
QGlyphLayout glyphs;
glyphs.numGlyphs = 1;
glyph_t glyph;
glyphs.glyphs = &glyph;
glyphs.advances = &advance;
int nglyphs = 1;
if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0))
Q_UNREACHABLE();
Q_ASSERT(nglyphs == 1);
engine->recalcAdvances(&glyphs, 0);
width = qRound(advance);
}
@ -739,16 +708,7 @@ QRect QFontMetrics::boundingRect(QChar ch) const
d->alterCharForCapitalization(ch);
glyph_t glyph;
QGlyphLayout glyphs;
glyphs.numGlyphs = 1;
glyphs.glyphs = &glyph;
int nglyphs = 1;
if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly))
Q_UNREACHABLE();
Q_ASSERT(nglyphs == 1);
glyph_t glyph = engine->glyphIndex(ch.unicode());
glyph_metrics_t gm = engine->boundingBox(glyph);
return QRect(qRound(gm.x), qRound(gm.y), qRound(gm.width), qRound(gm.height));
@ -1315,12 +1275,7 @@ qreal QFontMetricsF::averageCharWidth() const
*/
bool QFontMetricsF::inFont(QChar ch) const
{
const int script = ch.script();
QFontEngine *engine = d->engineForScript(script);
Q_ASSERT(engine != 0);
if (engine->type() == QFontEngine::Box)
return false;
return engine->canRender(&ch, 1);
return inFontUcs4(ch.unicode());
}
/*!
@ -1365,16 +1320,7 @@ qreal QFontMetricsF::leftBearing(QChar ch) const
d->alterCharForCapitalization(ch);
glyph_t glyph;
QGlyphLayout glyphs;
glyphs.numGlyphs = 1;
glyphs.glyphs = &glyph;
int nglyphs = 1;
if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly))
Q_UNREACHABLE();
Q_ASSERT(nglyphs == 1);
glyph_t glyph = engine->glyphIndex(ch.unicode());
qreal lb;
engine->getGlyphBearings(glyph, &lb);
@ -1407,16 +1353,7 @@ qreal QFontMetricsF::rightBearing(QChar ch) const
d->alterCharForCapitalization(ch);
glyph_t glyph;
QGlyphLayout glyphs;
glyphs.numGlyphs = 1;
glyphs.glyphs = &glyph;
int nglyphs = 1;
if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly))
Q_UNREACHABLE();
Q_ASSERT(nglyphs == 1);
glyph_t glyph = engine->glyphIndex(ch.unicode());
qreal rb;
engine->getGlyphBearings(glyph, 0, &rb);
@ -1484,18 +1421,14 @@ qreal QFontMetricsF::width(QChar ch) const
d->alterCharForCapitalization(ch);
glyph_t glyph = engine->glyphIndex(ch.unicode());
QFixed advance;
QGlyphLayout glyphs;
glyphs.numGlyphs = 1;
glyph_t glyph;
glyphs.glyphs = &glyph;
glyphs.advances = &advance;
int nglyphs = 1;
if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0))
Q_UNREACHABLE();
Q_ASSERT(nglyphs == 1);
engine->recalcAdvances(&glyphs, 0);
return advance.toReal();
}
@ -1559,16 +1492,7 @@ QRectF QFontMetricsF::boundingRect(QChar ch) const
d->alterCharForCapitalization(ch);
glyph_t glyph;
QGlyphLayout glyphs;
glyphs.numGlyphs = 1;
glyphs.glyphs = &glyph;
int nglyphs = 1;
if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly))
Q_UNREACHABLE();
Q_ASSERT(nglyphs == 1);
glyph_t glyph = engine->glyphIndex(ch.unicode());
glyph_metrics_t gm = engine->boundingBox(glyph);
return QRectF(gm.x.toReal(), gm.y.toReal(), gm.width.toReal(), gm.height.toReal());

View File

@ -201,22 +201,8 @@ static void checkRanges(QPdf::ByteStream &ts, QByteArray &ranges, int &nranges)
QVector<int> QFontSubset::getReverseMap() const
{
QVector<int> reverseMap(0x10000, 0);
glyph_t glyph;
QGlyphLayout glyphs;
glyphs.glyphs = &glyph;
glyphs.numGlyphs = 1;
for (uint uc = 0; uc < 0x10000; ++uc) {
QChar ch(uc);
int nglyphs = 1;
if (!fontEngine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly))
Q_UNREACHABLE();
Q_ASSERT(nglyphs == 1);
int idx = glyph_indices.indexOf(glyph);
int idx = glyph_indices.indexOf(fontEngine->glyphIndex(uc));
if (idx >= 0 && !reverseMap.at(idx))
reverseMap[idx] = uc;
}

View File

@ -397,33 +397,7 @@ _hb_qt_font_get_glyph(hb_font_t * /*font*/, void *font_data,
QFontEngine *fe = (QFontEngine *)font_data;
Q_ASSERT(fe);
QChar chars[2];
int numChars = 0;
if (Q_UNLIKELY(QChar::requiresSurrogates(unicode))) {
chars[numChars++] = QChar(QChar::highSurrogate(unicode));
chars[numChars++] = QChar(QChar::lowSurrogate(unicode));
} else {
chars[numChars++] = QChar(unicode);
}
#if 0
if (Q_UNLIKELY(variation_selector != 0)) {
if (Q_UNLIKELY(QChar::requiresSurrogates(variation_selector))) {
chars[numChars++] = QChar(QChar::highSurrogate(variation_selector));
chars[numChars++] = QChar(QChar::lowSurrogate(variation_selector));
} else {
chars[numChars++] = QChar(variation_selector);
}
}
#endif
QGlyphLayout g;
g.numGlyphs = numChars;
g.glyphs = glyph;
int numGlyphs = numChars;
if (!fe->stringToCMap(chars, numChars, &g, &numGlyphs, QFontEngine::GlyphIndicesOnly))
Q_UNREACHABLE();
Q_ASSERT(numGlyphs == 1);
*glyph = fe->glyphIndex(unicode);
return true;
}

View File

@ -665,7 +665,7 @@ QList<QFontDatabase::WritingSystem> QRawFont::supportedWritingSystems() const
*/
bool QRawFont::supportsCharacter(QChar character) const
{
return d->isValid() && d->fontEngine->canRender(&character, 1);
return supportsCharacter(character.unicode());
}
/*!

View File

@ -2011,21 +2011,16 @@ static void set(QJustificationPoint *point, int type, const QGlyphLayout &glyph,
if (type >= Justification_Arabic_Normal) {
QChar ch(0x640); // Kashida character
glyph_t kashidaGlyph;
QFixed kashidaWidth;
glyph_t kashidaGlyph = fe->glyphIndex(ch.unicode());
if (kashidaGlyph != 0) {
QGlyphLayout g;
g.numGlyphs = 1;
g.glyphs = &kashidaGlyph;
g.advances = &point->kashidaWidth;
fe->recalcAdvances(&g, 0);
QGlyphLayout glyphs;
glyphs.numGlyphs = 1;
glyphs.glyphs = &kashidaGlyph;
glyphs.advances = &kashidaWidth;
int nglyphs = 1;
if (!fe->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0))
Q_UNREACHABLE();
Q_ASSERT(nglyphs == 1);
if (kashidaGlyph != 0 && kashidaWidth != 0) {
point->kashidaWidth = kashidaWidth;
if (point->kashidaWidth == 0)
point->type = Justification_Prohibited;
} else {
point->type = Justification_Prohibited;
point->kashidaWidth = 0;
@ -2644,40 +2639,30 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int
QFixed ellipsisWidth;
QString ellipsisText;
{
QFontEngine *fe = fnt.d->engineForScript(QChar::Script_Common);
QFontEngine *engine = fe->type() == QFontEngine::Multi ? static_cast<QFontEngineMulti *>(fe)->engine(0) : fe;
QChar ellipsisChar(0x2026);
QFontEngine *fe = fnt.d->engineForScript(QChar::Script_Common);
glyph_t glyph = engine->glyphIndex(ellipsisChar.unicode());
QGlyphLayoutArray<1> ellipsisGlyph;
{
QFontEngine *feForEllipsis = (fe->type() == QFontEngine::Multi)
? static_cast<QFontEngineMulti *>(fe)->engine(0)
: fe;
QGlyphLayout glyphs;
glyphs.numGlyphs = 1;
glyphs.glyphs = &glyph;
glyphs.advances = &ellipsisWidth;
if (feForEllipsis->type() == QFontEngine::Mac)
feForEllipsis = fe;
if (glyph != 0) {
engine->recalcAdvances(&glyphs, 0);
int nGlyphs = 1;
if (!feForEllipsis->stringToCMap(&ellipsisChar, 1, &ellipsisGlyph, &nGlyphs, 0))
Q_UNREACHABLE();
Q_ASSERT(nGlyphs == 1);
}
if (ellipsisGlyph.glyphs[0]) {
ellipsisWidth = ellipsisGlyph.advances[0];
ellipsisText = ellipsisChar;
} else {
QString dotDotDot(QLatin1String("..."));
glyph = engine->glyphIndex('.');
if (glyph != 0) {
engine->recalcAdvances(&glyphs, 0);
QGlyphLayoutArray<3> glyphs;
int nGlyphs = 3;
if (!fe->stringToCMap(dotDotDot.constData(), 3, &glyphs, &nGlyphs, 0))
Q_UNREACHABLE();
Q_ASSERT(nGlyphs == 3);
for (int i = 0; i < nGlyphs; ++i)
ellipsisWidth += glyphs.advances[i];
ellipsisText = dotDotDot;
ellipsisWidth *= 3;
ellipsisText = QStringLiteral("...");
}
}
}