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:
Lars Knoll 2019-10-16 11:49:27 +02:00
parent 6f27bb1352
commit 2c47d53249
2 changed files with 66 additions and 34 deletions

View File

@ -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)

View File

@ -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();