diff --git a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp index 8c6cc8fbc1e..10f17f0258b 100644 --- a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp +++ b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp @@ -1354,6 +1354,53 @@ static inline FT_Matrix QTransformToFTMatrix(const QTransform &matrix) return m; } +QFontEngineFT::QGlyphSet *QFontEngineFT::TransformedGlyphSets::findSet(const QTransform &matrix, const QFontDef &fontDef) +{ + FT_Matrix m = QTransformToFTMatrix(matrix); + + int i = 0; + for (; i < nSets; ++i) { + QGlyphSet *g = sets[i]; + if (!g) + break; + if (g->transformationMatrix.xx == m.xx + && g->transformationMatrix.xy == m.xy + && g->transformationMatrix.yx == m.yx + && g->transformationMatrix.yy == m.yy) { + + // found a match, move it to the front + moveToFront(i); + return g; + } + } + + // don't cache more than nSets transformations + if (i == nSets) + // reuse the last set + --i; + moveToFront(nSets - 1); + if (!sets[0]) + sets[0] = new QGlyphSet; + QGlyphSet *gs = sets[0]; + gs->clear(); + gs->transformationMatrix = m; + gs->outline_drawing = fontDef.pixelSize * fontDef.pixelSize * qAbs(matrix.determinant()) > QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE; + Q_ASSERT(gs != 0); + + return gs; +} + +void QFontEngineFT::TransformedGlyphSets::moveToFront(int i) +{ + QGlyphSet *g = sets[i]; + while (i > 0) { + sets[i] = sets[i - 1]; + --i; + } + sets[0] = g; +} + + QFontEngineFT::QGlyphSet *QFontEngineFT::loadGlyphSet(const QTransform &matrix) { if (matrix.type() > QTransform::TxShear || !cacheEnabled) @@ -1363,39 +1410,7 @@ QFontEngineFT::QGlyphSet *QFontEngineFT::loadGlyphSet(const QTransform &matrix) if (!FT_IS_SCALABLE(freetype->face)) return matrix.type() <= QTransform::TxTranslate ? &defaultGlyphSet : nullptr; - FT_Matrix m = QTransformToFTMatrix(matrix); - - QGlyphSet *gs = 0; - - for (int i = 0; i < transformedGlyphSets.count(); ++i) { - const QGlyphSet &g = transformedGlyphSets.at(i); - if (g.transformationMatrix.xx == m.xx - && g.transformationMatrix.xy == m.xy - && g.transformationMatrix.yx == m.yx - && g.transformationMatrix.yy == m.yy) { - - // found a match, move it to the front - transformedGlyphSets.move(i, 0); - gs = &transformedGlyphSets[0]; - break; - } - } - - if (!gs) { - // don't cache more than 10 transformations - if (transformedGlyphSets.count() >= 10) { - transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0); - } else { - transformedGlyphSets.prepend(QGlyphSet()); - } - gs = &transformedGlyphSets[0]; - gs->clear(); - gs->transformationMatrix = m; - gs->outline_drawing = fontDef.pixelSize * fontDef.pixelSize * qAbs(matrix.determinant()) > QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE; - } - Q_ASSERT(gs != 0); - - return gs; + return transformedGlyphSets.findSet(matrix, fontDef); } void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics) diff --git a/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h b/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h index 2e3aef69790..8019588bf5b 100644 --- a/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h +++ b/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h @@ -63,6 +63,8 @@ #include +#include + QT_BEGIN_NAMESPACE class QFontEngineFTRawFont; @@ -170,6 +172,7 @@ public: inline bool isGlyphMissing(glyph_t index) const { return missing_glyphs.contains(index); } inline void setGlyphMissing(glyph_t index) const { missing_glyphs.insert(index); } private: + Q_DISABLE_COPY(QGlyphSet); mutable QHash glyph_data; // maps from glyph index to glyph data mutable QSet missing_glyphs; mutable Glyph *fast_glyph_data[256]; // for fast lookup of glyphs < 256 @@ -310,7 +313,18 @@ private: GlyphFormat defaultFormat; FT_Matrix matrix; - QList transformedGlyphSets; + struct TransformedGlyphSets { + enum { nSets = 10 }; + QGlyphSet *sets[nSets]; + + QGlyphSet *findSet(const QTransform &matrix, const QFontDef &fontDef); + TransformedGlyphSets() { std::fill(&sets[0], &sets[nSets], nullptr); } + ~TransformedGlyphSets() { qDeleteAll(&sets[0], &sets[nSets]); } + private: + void moveToFront(int i); + Q_DISABLE_COPY(TransformedGlyphSets); + }; + TransformedGlyphSets transformedGlyphSets; mutable QGlyphSet defaultGlyphSet; QFontEngine::FaceId face_id; @@ -326,6 +340,9 @@ private: QFixed scalableBitmapScaleFactor; }; +Q_DECLARE_TYPEINFO(QFontEngineFT::QGlyphSet, Q_MOVABLE_TYPE); + + inline uint qHash(const QFontEngineFT::GlyphAndSubPixelPosition &g) { return (g.glyph << 8) | (g.subPixelPosition * 10).round().toInt();