Fix leaking of QFontEngineData

QFontCache now references QFontEngineData-s it maintains,
so that QFont instances not freed prior to calling ~QFontCache()
would destroy QFontEngineData on their own.

Task-number: QTBUG-25434

Change-Id: Ia7679d64de436841f09ac7be62ceb570e50cce5b
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com>
Reviewed-by: jian liang <jianliang79@gmail.com>
This commit is contained in:
Konstantin Ritt 2013-04-07 16:29:22 +03:00 committed by The Qt Project
parent 289120f8dd
commit b3dae6848d
4 changed files with 25 additions and 15 deletions

View File

@ -191,8 +191,8 @@ QFontPrivate::QFontPrivate(const QFontPrivate &other)
QFontPrivate::~QFontPrivate()
{
if (engineData)
engineData->ref.deref();
if (engineData && !engineData->ref.deref())
delete engineData;
engineData = 0;
if (scFont && scFont != this)
scFont->ref.deref();
@ -210,7 +210,8 @@ QFontEngine *QFontPrivate::engineForScript(int script) const
script = QChar::Script_Common;
if (engineData && engineData->fontCache != QFontCache::instance()) {
// throw out engineData that came from a different thread
engineData->ref.deref();
if (!engineData->ref.deref())
delete engineData;
engineData = 0;
}
if (!engineData || !QT_FONT_ENGINE_FROM_DATA(engineData, script))
@ -316,13 +317,14 @@ void QFontPrivate::resolve(uint mask, const QFontPrivate *other)
QFontEngineData::QFontEngineData()
: ref(1), fontCache(QFontCache::instance())
: ref(0), fontCache(QFontCache::instance())
{
memset(engines, 0, QChar::ScriptCount * sizeof(QFontEngine *));
}
QFontEngineData::~QFontEngineData()
{
Q_ASSERT(ref.load() == 0);
for (int i = 0; i < QChar::ScriptCount; ++i) {
if (engines[i]) {
if (!engines[i]->ref.deref())
@ -637,8 +639,8 @@ QFont::QFont(QFontPrivate *data)
void QFont::detach()
{
if (d->ref.load() == 1) {
if (d->engineData)
d->engineData->ref.deref();
if (d->engineData && !d->engineData->ref.deref())
delete d->engineData;
d->engineData = 0;
if (d->scFont && d->scFont != d.data())
d->scFont->ref.deref();
@ -2641,7 +2643,7 @@ QFontCache::~QFontCache()
EngineDataCache::ConstIterator it = engineDataCache.constBegin(),
end = engineDataCache.constEnd();
while (it != end) {
if (it.value()->ref.load() == 0)
if (!it.value()->ref.deref())
delete it.value();
else
FC_DEBUG("QFontCache::~QFontCache: engineData %p still has refcount %d",
@ -2713,7 +2715,9 @@ void QFontCache::insertEngineData(const QFontDef &def, QFontEngineData *engineDa
def.pixelSize, def.weight, def.style, def.fixedPitch);
}
#endif
Q_ASSERT(!engineDataCache.contains(def));
engineData->ref.ref();
engineDataCache.insert(def, engineData);
increaseCost(sizeof(QFontEngineData));
}
@ -2829,7 +2833,7 @@ void QFontCache::timerEvent(QTimerEvent *)
for (; it != end; ++it) {
FC_DEBUG(" %p: ref %2d", it.value(), int(it.value()->ref.load()));
if (it.value()->ref.load() != 0)
if (it.value()->ref.load() != 1)
in_use_cost += engine_data_cost;
}
}
@ -2894,9 +2898,10 @@ void QFontCache::timerEvent(QTimerEvent *)
// clean out all unused engine data
EngineDataCache::Iterator it = engineDataCache.begin();
while (it != engineDataCache.end()) {
if (it.value()->ref.load() == 0) {
if (it.value()->ref.load() == 1) {
FC_DEBUG(" %p", it.value());
decreaseCost(sizeof(QFontEngineData));
it.value()->ref.deref();
delete it.value();
it = engineDataCache.erase(it);
} else {

View File

@ -143,6 +143,9 @@ public:
QFontCache *fontCache;
QFontEngine *engines[QChar::ScriptCount];
private:
Q_DISABLE_COPY(QFontEngineData)
};

View File

@ -619,9 +619,8 @@ static void getEngineData(const QFontPrivate *d, const QFontDef &def)
// create a new one
d->engineData = new QFontEngineData;
QFontCache::instance()->insertEngineData(def, d->engineData);
} else {
d->engineData->ref.ref();
}
d->engineData->ref.ref();
}
static QStringList familyList(const QFontDef &req)

View File

@ -690,33 +690,36 @@ void tst_QFont::defaultFamily()
void tst_QFont::sharing()
{
// QFontCache references the engineData
int refs_by_cache = 1;
QFont f;
f.setStyleHint(QFont::Serif);
f.exactMatch(); // loads engine
QCOMPARE(QFontPrivate::get(f)->ref.load(), 1);
QVERIFY(QFontPrivate::get(f)->engineData);
QCOMPARE(QFontPrivate::get(f)->engineData->ref.load(), 1);
QCOMPARE(QFontPrivate::get(f)->engineData->ref.load(), 1 + refs_by_cache);
QFont f2(f);
QVERIFY(QFontPrivate::get(f2) == QFontPrivate::get(f));
QCOMPARE(QFontPrivate::get(f2)->ref.load(), 2);
QVERIFY(QFontPrivate::get(f2)->engineData);
QVERIFY(QFontPrivate::get(f2)->engineData == QFontPrivate::get(f)->engineData);
QCOMPARE(QFontPrivate::get(f2)->engineData->ref.load(), 1);
QCOMPARE(QFontPrivate::get(f2)->engineData->ref.load(), 1 + refs_by_cache);
f2.setKerning(!f.kerning());
QVERIFY(QFontPrivate::get(f2) != QFontPrivate::get(f));
QCOMPARE(QFontPrivate::get(f2)->ref.load(), 1);
QVERIFY(QFontPrivate::get(f2)->engineData);
QVERIFY(QFontPrivate::get(f2)->engineData == QFontPrivate::get(f)->engineData);
QCOMPARE(QFontPrivate::get(f2)->engineData->ref.load(), 2);
QCOMPARE(QFontPrivate::get(f2)->engineData->ref.load(), 2 + refs_by_cache);
f2 = f;
QVERIFY(QFontPrivate::get(f2) == QFontPrivate::get(f));
QCOMPARE(QFontPrivate::get(f2)->ref.load(), 2);
QVERIFY(QFontPrivate::get(f2)->engineData);
QVERIFY(QFontPrivate::get(f2)->engineData == QFontPrivate::get(f)->engineData);
QCOMPARE(QFontPrivate::get(f2)->engineData->ref.load(), 1);
QCOMPARE(QFontPrivate::get(f2)->engineData->ref.load(), 1 + refs_by_cache);
if (f.pointSize() > 0)
f2.setPointSize(f.pointSize() * 2 / 3);