--- /dev/null
+From 45693cc638d10890f2816a38d38de6ddaf04ffd3 Mon Sep 17 00:00:00 2001
+From: Simon Yuan <simon.yuan@navico.com>
+Date: Wed, 2 Apr 2014 16:02:04 +1300
+Subject: [PATCH 30/74] Memory and file descriptor leak in QFontCache
+
+Make the cache also use the ref counts
+Make everyone who decrements a ref count check for 0 and delete
+Move all cache logic to the cache
+Same idea as 36cb3f3 and b3dae68 in Qt 5 without the extra stuff
+
+Task-number: QTBUG-38035
+Change-Id: I27bea376f4ec0888463b4ec3ed1a6bef00d041f8
+Reviewed-by: Konstantin Ritt <ritt.ks@gmail.com>
+Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com>
+---
+ src/gui/text/qfont.cpp | 102 +++++++++++++++++-------------------------
+ src/gui/text/qfontengine.cpp | 7 +--
+ src/gui/text/qrawfont.cpp | 13 +++---
+ src/gui/text/qrawfont_win.cpp | 4 +-
+ src/gui/text/qstatictext.cpp | 6 +--
+ src/gui/text/qtextengine.cpp | 7 +--
+ 6 files changed, 55 insertions(+), 84 deletions(-)
+
+diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp
+index 7e94c1e..fa9bb70 100644
+--- a/src/gui/text/qfont.cpp
++++ b/src/gui/text/qfont.cpp
+@@ -275,8 +275,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();
+@@ -298,7 +298,8 @@ QFontEngine *QFontPrivate::engineForScript(int script) const
+ script = QUnicodeTables::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))
+@@ -417,13 +418,13 @@ QFontEngineData::~QFontEngineData()
+ {
+ #if !defined(Q_WS_MAC)
+ for (int i = 0; i < QUnicodeTables::ScriptCount; ++i) {
+- if (engines[i])
+- engines[i]->ref.deref();
++ if (engines[i] && !engines[i]->ref.deref())
++ delete engines[i];
+ engines[i] = 0;
+ }
+ #else
+- if (engine)
+- engine->ref.deref();
++ if (engine && !engine->ref.deref())
++ delete engine;
+ engine = 0;
+ #endif // Q_WS_X11 || Q_WS_WIN || Q_WS_MAC
+ }
+@@ -770,8 +771,8 @@ QFont::QFont(QFontPrivate *data)
+ void QFont::detach()
+ {
+ if (d->ref == 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();
+@@ -2819,7 +2820,7 @@ QFontCache::~QFontCache()
+ EngineDataCache::ConstIterator it = engineDataCache.constBegin(),
+ end = engineDataCache.constEnd();
+ while (it != end) {
+- if (it.value()->ref == 0)
++ if (it.value()->ref.deref() == 0)
+ delete it.value();
+ else
+ FC_DEBUG("QFontCache::~QFontCache: engineData %p still has refcount %d",
+@@ -2827,24 +2828,6 @@ QFontCache::~QFontCache()
+ ++it;
+ }
+ }
+- EngineCache::ConstIterator it = engineCache.constBegin(),
+- end = engineCache.constEnd();
+- while (it != end) {
+- if (--it.value().data->cache_count == 0) {
+- if (it.value().data->ref == 0) {
+- FC_DEBUG("QFontCache::~QFontCache: deleting engine %p key=(%d / %g %g %d %d %d)",
+- it.value().data, it.key().script, it.key().def.pointSize,
+- it.key().def.pixelSize, it.key().def.weight, it.key().def.style,
+- it.key().def.fixedPitch);
+-
+- delete it.value().data;
+- } else {
+- FC_DEBUG("QFontCache::~QFontCache: engine = %p still has refcount %d",
+- it.value().data, int(it.value().data->ref));
+- }
+- }
+- ++it;
+- }
+ }
+
+ void QFontCache::clear()
+@@ -2856,16 +2839,14 @@ void QFontCache::clear()
+ QFontEngineData *data = it.value();
+ #if !defined(Q_WS_MAC)
+ for (int i = 0; i < QUnicodeTables::ScriptCount; ++i) {
+- if (data->engines[i]) {
+- data->engines[i]->ref.deref();
+- data->engines[i] = 0;
+- }
++ if (data->engines[i] && !data->engines[i]->ref.deref())
++ delete data->engines[i];
++ data->engines[i] = 0;
+ }
+ #else
+- if (data->engine) {
+- data->engine->ref.deref();
+- data->engine = 0;
+- }
++ if (data->engine && !data->engine->ref.deref())
++ delete data->engine;
++ data->engine = 0;
+ #endif
+ ++it;
+ }
+@@ -2873,15 +2854,7 @@ void QFontCache::clear()
+
+ for (EngineCache::Iterator it = engineCache.begin(), end = engineCache.end();
+ it != end; ++it) {
+- if (it->data->ref == 0) {
+- delete it->data;
+- it->data = 0;
+- }
+- }
+-
+- for (EngineCache::Iterator it = engineCache.begin(), end = engineCache.end();
+- it != end; ++it) {
+- if (it->data && it->data->ref == 0) {
++ if (it->data->ref.deref() == 0) {
+ delete it->data;
+ it->data = 0;
+ }
+@@ -2916,6 +2889,8 @@ void QFontCache::insertEngineData(const Key &key, QFontEngineData *engineData)
+ {
+ FC_DEBUG("QFontCache: inserting new engine data %p", engineData);
+
++ Q_ASSERT(!engineDataCache.contains(key));
++ engineData->ref.ref(); // the cache has a reference
+ engineDataCache.insert(key, engineData);
+ increaseCost(sizeof(QFontEngineData));
+ }
+@@ -2946,6 +2921,11 @@ void QFontCache::insertEngine(const Key &key, QFontEngine *engine)
+ Engine data(engine);
+ data.timestamp = ++current_timestamp;
+
++ QFontEngine *oldEngine = engineCache.value(key).data;
++ engine->ref.ref(); // the cache has a reference
++ if (oldEngine && !oldEngine->ref.deref())
++ delete oldEngine;
++
+ engineCache.insert(key, data);
+
+ // only increase the cost if this is the first time we insert the engine
+@@ -3005,12 +2985,11 @@ void QFontCache::cleanupPrinterFonts()
+ continue;
+ }
+
+- if(it.value()->ref != 0) {
+- for(int i = 0; i < QUnicodeTables::ScriptCount; ++i) {
+- if(it.value()->engines[i]) {
+- it.value()->engines[i]->ref.deref();
+- it.value()->engines[i] = 0;
+- }
++ if (it.value()->ref > 1) {
++ for (int i = 0; i < QUnicodeTables::ScriptCount; ++i) {
++ if (it.value()->engines[i] && !it.value()->engines[i]->ref.deref())
++ delete it.value()->engines[i];
++ it.value()->engines[i] = 0;
+ }
+ ++it;
+ } else {
+@@ -3021,7 +3000,8 @@ void QFontCache::cleanupPrinterFonts()
+
+ FC_DEBUG(" %p", rem.value());
+
+- delete rem.value();
++ if (!rem.value()->ref.deref())
++ delete rem.value();
+ engineDataCache.erase(rem);
+ }
+ }
+@@ -3030,7 +3010,7 @@ void QFontCache::cleanupPrinterFonts()
+ EngineCache::Iterator it = engineCache.begin(),
+ end = engineCache.end();
+ while(it != end) {
+- if (it.value().data->ref != 0 || it.key().screen == 0) {
++ if (it.value().data->ref != 1 || it.key().screen == 0) {
+ ++it;
+ continue;
+ }
+@@ -3044,7 +3024,8 @@ void QFontCache::cleanupPrinterFonts()
+ FC_DEBUG(" DELETE: last occurrence in cache");
+
+ decreaseCost(it.value().data->cache_cost);
+- delete it.value().data;
++ if (!it.value().data->ref.deref())
++ delete it.value().data;
+ }
+
+ engineCache.erase(it++);
+@@ -3093,7 +3074,7 @@ void QFontCache::timerEvent(QTimerEvent *)
+ # endif // Q_WS_X11 || Q_WS_WIN
+ #endif // QFONTCACHE_DEBUG
+
+- if (it.value()->ref != 0)
++ if (it.value()->ref > 1)
+ in_use_cost += engine_data_cost;
+ }
+ }
+@@ -3109,7 +3090,7 @@ void QFontCache::timerEvent(QTimerEvent *)
+ int(it.value().data->ref), it.value().data->cache_count,
+ it.value().data->cache_cost);
+
+- if (it.value().data->ref != 0)
++ if (it.value().data->ref > 1)
+ in_use_cost += it.value().data->cache_cost / it.value().data->cache_count;
+ }
+
+@@ -3159,7 +3140,7 @@ void QFontCache::timerEvent(QTimerEvent *)
+ EngineDataCache::Iterator it = engineDataCache.begin(),
+ end = engineDataCache.end();
+ while (it != end) {
+- if (it.value()->ref != 0) {
++ if (it.value()->ref > 1) {
+ ++it;
+ continue;
+ }
+@@ -3187,7 +3168,7 @@ void QFontCache::timerEvent(QTimerEvent *)
+ uint least_popular = ~0u;
+
+ for (; it != end; ++it) {
+- if (it.value().data->ref != 0)
++ if (it.value().data->ref > 1)
+ continue;
+
+ if (it.value().timestamp < oldest &&
+@@ -3200,7 +3181,7 @@ void QFontCache::timerEvent(QTimerEvent *)
+ FC_DEBUG(" oldest %u least popular %u", oldest, least_popular);
+
+ for (it = engineCache.begin(); it != end; ++it) {
+- if (it.value().data->ref == 0 &&
++ if (it.value().data->ref == 1 &&
+ it.value().timestamp == oldest &&
+ it.value().hits == least_popular)
+ break;
+@@ -3216,7 +3197,8 @@ void QFontCache::timerEvent(QTimerEvent *)
+ FC_DEBUG(" DELETE: last occurrence in cache");
+
+ decreaseCost(it.value().data->cache_cost);
+- delete it.value().data;
++ if (!it.value().data->ref.deref())
++ delete it.value().data;
+ } else {
+ /*
+ this particular font engine is in the cache multiple
+diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
+index 9de475c..bf108c4 100644
+--- a/src/gui/text/qfontengine.cpp
++++ b/src/gui/text/qfontengine.cpp
+@@ -1325,11 +1325,8 @@ QFontEngineMulti::~QFontEngineMulti()
+ {
+ for (int i = 0; i < engines.size(); ++i) {
+ QFontEngine *fontEngine = engines.at(i);
+- if (fontEngine) {
+- fontEngine->ref.deref();
+- if (fontEngine->cache_count == 0 && fontEngine->ref == 0)
+- delete fontEngine;
+- }
++ if (fontEngine && !fontEngine->ref.deref())
++ delete fontEngine;
+ }
+ }
+
+diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp
+index 2b7554a..cb2bcb3 100644
+--- a/src/gui/text/qrawfont.cpp
++++ b/src/gui/text/qrawfont.cpp
+@@ -682,8 +682,7 @@ void QRawFont::setPixelSize(qreal pixelSize)
+ if (d->fontEngine != 0)
+ d->fontEngine->ref.ref();
+
+- oldFontEngine->ref.deref();
+- if (oldFontEngine->cache_count == 0 && oldFontEngine->ref == 0)
++ if (!oldFontEngine->ref.deref())
+ delete oldFontEngine;
+ }
+
+@@ -693,12 +692,10 @@ void QRawFont::setPixelSize(qreal pixelSize)
+ void QRawFontPrivate::cleanUp()
+ {
+ platformCleanUp();
+- if (fontEngine != 0) {
+- fontEngine->ref.deref();
+- if (fontEngine->cache_count == 0 && fontEngine->ref == 0)
+- delete fontEngine;
+- fontEngine = 0;
+- }
++ if (fontEngine != 0 && !fontEngine->ref.deref())
++ delete fontEngine;
++ fontEngine = 0;
++
+ hintingPreference = QFont::PreferDefaultHinting;
+ }
+
+diff --git a/src/gui/text/qrawfont_win.cpp b/src/gui/text/qrawfont_win.cpp
+index 6923aae..9b66886 100644
+--- a/src/gui/text/qrawfont_win.cpp
++++ b/src/gui/text/qrawfont_win.cpp
+@@ -600,11 +600,11 @@ void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData,
+ if (request.family != fontEngine->fontDef.family) {
+ qWarning("QRawFont::platformLoadFromData: Failed to load font. "
+ "Got fallback instead: %s", qPrintable(fontEngine->fontDef.family));
+- if (fontEngine->cache_count == 0 && fontEngine->ref == 0)
++ if (fontEngine->ref == 0)
+ delete fontEngine;
+ fontEngine = 0;
+ } else {
+- Q_ASSERT(fontEngine->cache_count == 0 && fontEngine->ref == 0);
++ Q_ASSERT(fontEngine->ref == 0);
+
+ // Override the generated font name
+ static_cast<QFontEngineWin *>(fontEngine)->uniqueFamilyName = uniqueFamilyName;
+diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp
+index 657da33..b111200 100644
+--- a/src/gui/text/qstatictext.cpp
++++ b/src/gui/text/qstatictext.cpp
+@@ -724,10 +724,8 @@ QStaticTextItem::~QStaticTextItem()
+
+ void QStaticTextItem::setFontEngine(QFontEngine *fe)
+ {
+- if (m_fontEngine != 0) {
+- if (!m_fontEngine->ref.deref())
+- delete m_fontEngine;
+- }
++ if (m_fontEngine != 0 && !m_fontEngine->ref.deref())
++ delete m_fontEngine;
+
+ m_fontEngine = fe;
+ if (m_fontEngine != 0)
+diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
+index b371237..f4b86b0 100644
+--- a/src/gui/text/qtextengine.cpp
++++ b/src/gui/text/qtextengine.cpp
+@@ -1453,11 +1453,8 @@ void QTextEngine::shape(int item) const
+
+ static inline void releaseCachedFontEngine(QFontEngine *fontEngine)
+ {
+- if (fontEngine) {
+- fontEngine->ref.deref();
+- if (fontEngine->cache_count == 0 && fontEngine->ref == 0)
+- delete fontEngine;
+- }
++ if (fontEngine && !fontEngine->ref.deref())
++ delete fontEngine;
+ }
+
+ void QTextEngine::resetFontEngineCache()
+--
+1.9.3
+