summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2019-10-16 11:49:27 +0200
committerLars Knoll <lars.knoll@qt.io>2019-10-17 13:11:49 +0200
commit2c47d532490778e382b342907259c6dd11525f23 (patch)
treeceb4e014244889115b2128d18872c428d6286f59
parent6f27bb135246b7fe9d11ba58e05d2b7661bc2080 (diff)
Don't use a QList on a type that can't be copied
QGlyphSet would not copy correctly, but also didn't have a Q_DISABLE_COPY defined. This can easily lead to undefined behavior, and was visible when trying to do the QList to QVector conversion. As we only have a 10 item large LRU list here, implement it manually. Change-Id: I903085ddeac59224715dca6e8a1ff26c44f5b0b0 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r--src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp77
-rw-r--r--src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h19
2 files changed, 64 insertions, 32 deletions
diff --git a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
index 8c6cc8fbc1..10f17f0258 100644
--- a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
+++ b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
@@ -1354,50 +1354,65 @@ static inline FT_Matrix QTransformToFTMatrix(const QTransform &matrix)
return m;
}
-QFontEngineFT::QGlyphSet *QFontEngineFT::loadGlyphSet(const QTransform &matrix)
+QFontEngineFT::QGlyphSet *QFontEngineFT::TransformedGlyphSets::findSet(const QTransform &matrix, const QFontDef &fontDef)
{
- if (matrix.type() > QTransform::TxShear || !cacheEnabled)
- return 0;
-
- // FT_Set_Transform only supports scalable fonts
- 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) {
+ 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
- transformedGlyphSets.move(i, 0);
- gs = &transformedGlyphSets[0];
- break;
+ moveToFront(i);
+ return g;
}
}
- 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;
- }
+ // 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)
+ return 0;
+
+ // FT_Set_Transform only supports scalable fonts
+ if (!FT_IS_SCALABLE(freetype->face))
+ return matrix.type() <= QTransform::TxTranslate ? &defaultGlyphSet : nullptr;
+
+ return transformedGlyphSets.findSet(matrix, fontDef);
+}
+
void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
{
FT_Face face = lockFace(Unscaled);
diff --git a/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h b/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h
index 2e3aef6979..8019588bf5 100644
--- a/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h
+++ b/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h
@@ -63,6 +63,8 @@
#include <qmutex.h>
+#include <string.h>
+
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<GlyphAndSubPixelPosition, Glyph *> glyph_data; // maps from glyph index to glyph data
mutable QSet<glyph_t> 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<QGlyphSet> 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();