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>
This commit is contained in:
parent
6f27bb1352
commit
2c47d53249
@ -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)
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user