mirror of
https://bitbucket.org/smil3y/katie.git
synced 2025-02-25 03:12:56 +00:00
simplify fonts cache
Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
parent
7b68bf1f8f
commit
1024c78194
8 changed files with 19 additions and 296 deletions
|
@ -2309,19 +2309,6 @@ bool QFontInfo::exactMatch() const
|
|||
|
||||
// **********************************************************************
|
||||
// QFontCache
|
||||
// **********************************************************************
|
||||
|
||||
#ifdef QFONTCACHE_DEBUG
|
||||
// fast timeouts for debugging
|
||||
static const int fast_timeout = 1000; // 1s
|
||||
static const int slow_timeout = 5000; // 5s
|
||||
#else
|
||||
static const int fast_timeout = 10000; // 10s
|
||||
static const int slow_timeout = 300000; // 5m
|
||||
#endif // QFONTCACHE_DEBUG
|
||||
|
||||
const uint QFontCache::min_cost = 4*1024; // 4mb
|
||||
|
||||
thread_local QFontCache* theFontCache = nullptr;
|
||||
|
||||
QFontCache *QFontCache::instance()
|
||||
|
@ -2340,8 +2327,6 @@ void QFontCache::cleanup()
|
|||
}
|
||||
|
||||
QFontCache::QFontCache()
|
||||
: QObject(), total_cost(0), max_cost(min_cost),
|
||||
current_timestamp(0), fast(false), timer_id(-1)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -2380,9 +2365,9 @@ void QFontCache::clear()
|
|||
|
||||
for (EngineCache::Iterator it = engineCache.begin(), end = engineCache.end();
|
||||
it != end; ++it) {
|
||||
if (!it->data->ref.deref()) {
|
||||
delete it->data;
|
||||
it->data = 0;
|
||||
QFontEngine *engine = it.value();
|
||||
if (!engine->ref.deref()) {
|
||||
delete engine;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2394,7 +2379,9 @@ QFontEngineData *QFontCache::findEngineData(const Key &key) const
|
|||
{
|
||||
EngineDataCache::ConstIterator it = engineDataCache.find(key),
|
||||
end = engineDataCache.end();
|
||||
if (it == end) return 0;
|
||||
if (it == end) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// found
|
||||
return it.value();
|
||||
|
@ -2407,263 +2394,35 @@ void QFontCache::insertEngineData(const Key &key, QFontEngineData *engineData)
|
|||
Q_ASSERT(!engineDataCache.contains(key));
|
||||
engineData->ref.ref(); // the cache has a reference
|
||||
engineDataCache.insert(key, engineData);
|
||||
increaseCost(sizeof(QFontEngineData));
|
||||
}
|
||||
|
||||
QFontEngine *QFontCache::findEngine(const Key &key)
|
||||
{
|
||||
EngineCache::Iterator it = engineCache.find(key),
|
||||
end = engineCache.end();
|
||||
if (it == end) return 0;
|
||||
|
||||
// found... update the hitcount and timestamp
|
||||
it.value().hits++;
|
||||
it.value().timestamp = ++current_timestamp;
|
||||
if (it == end) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FC_DEBUG("QFontCache: found font engine\n"
|
||||
" %p: timestamp %4u hits %3u ref %2d/%2d, type '%s'",
|
||||
it.value().data, it.value().timestamp, it.value().hits,
|
||||
int(it.value().data->ref), it.value().data->cache_count,
|
||||
it.value().data->name());
|
||||
" %p: ref %2d, type '%s'",
|
||||
it.value(), int(it.value()->ref), it.value()->name());
|
||||
|
||||
return it.value().data;
|
||||
return it.value();
|
||||
}
|
||||
|
||||
void QFontCache::insertEngine(const Key &key, QFontEngine *engine)
|
||||
{
|
||||
FC_DEBUG("QFontCache: inserting new engine %p", engine);
|
||||
|
||||
Engine data(engine);
|
||||
data.timestamp = ++current_timestamp;
|
||||
|
||||
QFontEngine *oldEngine = engineCache.value(key).data;
|
||||
QFontEngine *oldEngine = engineCache.value(key);
|
||||
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
|
||||
if (engine->cache_count == 0)
|
||||
increaseCost(engine->cache_cost);
|
||||
|
||||
++engine->cache_count;
|
||||
engineCache.insert(key, engine);
|
||||
}
|
||||
|
||||
void QFontCache::increaseCost(uint cost)
|
||||
{
|
||||
cost = (cost + 512) / 1024; // store cost in kb
|
||||
cost = cost > 0 ? cost : 1;
|
||||
total_cost += cost;
|
||||
|
||||
FC_DEBUG(" COST: increased %u kb, total_cost %u kb, max_cost %u kb",
|
||||
cost, total_cost, max_cost);
|
||||
|
||||
if (total_cost > max_cost) {
|
||||
max_cost = total_cost;
|
||||
|
||||
if (timer_id == -1 || ! fast) {
|
||||
FC_DEBUG(" TIMER: starting fast timer (%d ms)", fast_timeout);
|
||||
|
||||
if (timer_id != -1) killTimer(timer_id);
|
||||
timer_id = startTimer(fast_timeout);
|
||||
fast = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QFontCache::decreaseCost(uint cost)
|
||||
{
|
||||
cost = (cost + 512) / 1024; // cost is stored in kb
|
||||
cost = cost > 0 ? cost : 1;
|
||||
Q_ASSERT(cost <= total_cost);
|
||||
total_cost -= cost;
|
||||
|
||||
FC_DEBUG(" COST: decreased %u kb, total_cost %u kb, max_cost %u kb",
|
||||
cost, total_cost, max_cost);
|
||||
}
|
||||
|
||||
void QFontCache::timerEvent(QTimerEvent *)
|
||||
{
|
||||
FC_DEBUG("QFontCache::timerEvent: performing cache maintenance (timestamp %u)",
|
||||
current_timestamp);
|
||||
|
||||
if (total_cost <= max_cost && max_cost <= min_cost) {
|
||||
FC_DEBUG(" cache redused sufficiently, stopping timer");
|
||||
|
||||
killTimer(timer_id);
|
||||
timer_id = -1;
|
||||
fast = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// go through the cache and count up everything in use
|
||||
uint in_use_cost = 0;
|
||||
|
||||
{
|
||||
FC_DEBUG(" SWEEP engine data:");
|
||||
|
||||
// make sure the cost of each engine data is at least 1kb
|
||||
const uint engine_data_cost =
|
||||
sizeof(QFontEngineData) > 1024 ? sizeof(QFontEngineData) : 1024;
|
||||
|
||||
EngineDataCache::ConstIterator it = engineDataCache.constBegin(),
|
||||
end = engineDataCache.constEnd();
|
||||
for (; it != end; ++it) {
|
||||
#ifdef QFONTCACHE_DEBUG
|
||||
FC_DEBUG(" %p: ref %2d", it.value(), int(it.value()->ref));
|
||||
|
||||
# if defined(Q_WS_X11)
|
||||
// print out all engines
|
||||
for (int i = 0; i < QUnicodeTables::ScriptCount; ++i) {
|
||||
if (! it.value()->engines[i])
|
||||
continue;
|
||||
FC_DEBUG(" contains %p", it.value()->engines[i]);
|
||||
}
|
||||
# endif // Q_WS_X11
|
||||
#endif // QFONTCACHE_DEBUG
|
||||
|
||||
if (it.value()->ref > 1)
|
||||
in_use_cost += engine_data_cost;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
FC_DEBUG(" SWEEP engine:");
|
||||
|
||||
EngineCache::ConstIterator it = engineCache.constBegin(),
|
||||
end = engineCache.constEnd();
|
||||
for (; it != end; ++it) {
|
||||
FC_DEBUG(" %p: timestamp %4u hits %2u ref %2d/%2d, cost %u bytes",
|
||||
it.value().data, it.value().timestamp, it.value().hits,
|
||||
int(it.value().data->ref), it.value().data->cache_count,
|
||||
it.value().data->cache_cost);
|
||||
|
||||
if (it.value().data->ref > 1)
|
||||
in_use_cost += it.value().data->cache_cost / it.value().data->cache_count;
|
||||
}
|
||||
|
||||
// attempt to make up for rounding errors
|
||||
in_use_cost += engineCache.size();
|
||||
}
|
||||
|
||||
in_use_cost = (in_use_cost + 512) / 1024; // cost is stored in kb
|
||||
|
||||
/*
|
||||
calculate the new maximum cost for the cache
|
||||
|
||||
NOTE: in_use_cost is *not* correct due to rounding errors in the
|
||||
above algorithm. instead of worrying about getting the
|
||||
calculation correct, we are more interested in speed, and use
|
||||
in_use_cost as a floor for new_max_cost
|
||||
*/
|
||||
uint new_max_cost = qMax(qMax(max_cost / 2, in_use_cost), min_cost);
|
||||
|
||||
FC_DEBUG(" after sweep, in use %u kb, total %u kb, max %u kb, new max %u kb",
|
||||
in_use_cost, total_cost, max_cost, new_max_cost);
|
||||
|
||||
if (new_max_cost == max_cost) {
|
||||
if (fast) {
|
||||
FC_DEBUG(" cannot shrink cache, slowing timer");
|
||||
|
||||
killTimer(timer_id);
|
||||
timer_id = startTimer(slow_timeout);
|
||||
fast = false;
|
||||
}
|
||||
|
||||
return;
|
||||
} else if (! fast) {
|
||||
FC_DEBUG(" dropping into passing gear");
|
||||
|
||||
killTimer(timer_id);
|
||||
timer_id = startTimer(fast_timeout);
|
||||
fast = true;
|
||||
}
|
||||
|
||||
max_cost = new_max_cost;
|
||||
|
||||
{
|
||||
FC_DEBUG(" CLEAN engine data:");
|
||||
|
||||
// clean out all unused engine data
|
||||
EngineDataCache::Iterator it = engineDataCache.begin(),
|
||||
end = engineDataCache.end();
|
||||
while (it != end) {
|
||||
if (it.value()->ref > 1) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
EngineDataCache::Iterator rem = it++;
|
||||
|
||||
decreaseCost(sizeof(QFontEngineData));
|
||||
|
||||
FC_DEBUG(" %p", rem.value());
|
||||
|
||||
delete rem.value();
|
||||
engineDataCache.erase(rem);
|
||||
}
|
||||
}
|
||||
|
||||
// clean out the engine cache just enough to get below our new max cost
|
||||
uint current_cost;
|
||||
do {
|
||||
current_cost = total_cost;
|
||||
|
||||
EngineCache::Iterator it = engineCache.begin(),
|
||||
end = engineCache.end();
|
||||
// determine the oldest and least popular of the unused engines
|
||||
uint oldest = ~0u;
|
||||
uint least_popular = ~0u;
|
||||
|
||||
for (; it != end; ++it) {
|
||||
if (it.value().data->ref > 1)
|
||||
continue;
|
||||
|
||||
if (it.value().timestamp < oldest &&
|
||||
it.value().hits <= least_popular) {
|
||||
oldest = it.value().timestamp;
|
||||
least_popular = it.value().hits;
|
||||
}
|
||||
}
|
||||
|
||||
FC_DEBUG(" oldest %u least popular %u", oldest, least_popular);
|
||||
|
||||
for (it = engineCache.begin(); it != end; ++it) {
|
||||
if (it.value().data->ref == 1 &&
|
||||
it.value().timestamp == oldest &&
|
||||
it.value().hits == least_popular)
|
||||
break;
|
||||
}
|
||||
|
||||
if (it != end) {
|
||||
FC_DEBUG(" %p: timestamp %4u hits %2u ref %2d/%2d, type '%s'",
|
||||
it.value().data, it.value().timestamp, it.value().hits,
|
||||
int(it.value().data->ref), it.value().data->cache_count,
|
||||
it.value().data->name());
|
||||
|
||||
if (--it.value().data->cache_count == 0) {
|
||||
FC_DEBUG(" DELETE: last occurrence in cache");
|
||||
|
||||
decreaseCost(it.value().data->cache_cost);
|
||||
if (!it.value().data->ref.deref())
|
||||
delete it.value().data;
|
||||
} else {
|
||||
/*
|
||||
this particular font engine is in the cache multiple
|
||||
times... set current_cost to zero, so that we can
|
||||
keep looping to get rid of all occurrences
|
||||
*/
|
||||
current_cost = 0;
|
||||
}
|
||||
|
||||
engineCache.erase(it);
|
||||
}
|
||||
} while (current_cost != total_cost && total_cost > max_cost);
|
||||
}
|
||||
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
QDebug operator<<(QDebug stream, const QFont &font)
|
||||
{
|
||||
|
@ -2674,4 +2433,3 @@ QDebug operator<<(QDebug stream, const QFont &font)
|
|||
QT_END_NAMESPACE
|
||||
|
||||
#include "moc_qfont.h"
|
||||
#include "moc_qfont_p.h"
|
||||
|
|
|
@ -163,9 +163,8 @@ private:
|
|||
};
|
||||
|
||||
|
||||
class QFontCache : public QObject
|
||||
class QFontCache
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
// note: these static functions work on a per-thread basis
|
||||
static QFontCache *instance();
|
||||
|
@ -204,31 +203,11 @@ public:
|
|||
void insertEngineData(const Key &key, QFontEngineData *engineData);
|
||||
|
||||
// QFontEngine cache
|
||||
struct Engine {
|
||||
Engine() : data(0), timestamp(0), hits(0) { }
|
||||
Engine(QFontEngine *d) : data(d), timestamp(0), hits(0) { }
|
||||
|
||||
QFontEngine *data;
|
||||
uint timestamp;
|
||||
uint hits;
|
||||
};
|
||||
|
||||
typedef QMap<Key,Engine> EngineCache;
|
||||
typedef QMap<Key,QFontEngine *> EngineCache;
|
||||
EngineCache engineCache;
|
||||
|
||||
QFontEngine *findEngine(const Key &key);
|
||||
void insertEngine(const Key &key, QFontEngine *engine);
|
||||
|
||||
private:
|
||||
void increaseCost(uint cost);
|
||||
void decreaseCost(uint cost);
|
||||
void timerEvent(QTimerEvent *event);
|
||||
|
||||
static const uint min_cost;
|
||||
uint total_cost, max_cost;
|
||||
uint current_timestamp;
|
||||
bool fast;
|
||||
int timer_id;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
@ -141,7 +141,6 @@ QFontEngine::QFontEngine()
|
|||
: QObject(),
|
||||
ref(0)
|
||||
{
|
||||
cache_count = 0;
|
||||
fsType = 0;
|
||||
symbol = false;
|
||||
memset(&hbFont, 0, sizeof(hbFont));
|
||||
|
@ -709,7 +708,6 @@ QByteArray QFontEngine::convertToPostscriptFontFamilyName(const QByteArray &fami
|
|||
QFontEngineBox::QFontEngineBox(int size)
|
||||
: _size(size)
|
||||
{
|
||||
cache_cost = sizeof(QFontEngineBox);
|
||||
}
|
||||
|
||||
QFontEngineBox::~QFontEngineBox()
|
||||
|
@ -845,7 +843,6 @@ static inline glyph_t stripped(glyph_t glyph)
|
|||
QFontEngineMulti::QFontEngineMulti(int engineCount)
|
||||
{
|
||||
engines.fill(0, engineCount);
|
||||
cache_cost = 0;
|
||||
}
|
||||
|
||||
QFontEngineMulti::~QFontEngineMulti()
|
||||
|
|
|
@ -19,9 +19,6 @@
|
|||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qdir.h"
|
||||
#include "qmetatype.h"
|
||||
#include "qtextstream.h"
|
||||
#include "qvariant.h"
|
||||
#include "qfile.h"
|
||||
#include "qabstractfileengine.h"
|
||||
|
@ -375,7 +372,6 @@ QFontEngineFT::QFontEngineFT(const QFontDef &fd)
|
|||
matrix.yy = 0x10000;
|
||||
matrix.xy = 0;
|
||||
matrix.yx = 0;
|
||||
cache_cost = 100;
|
||||
kerning_pairs_loaded = false;
|
||||
embolden = false;
|
||||
freetype = 0;
|
||||
|
|
|
@ -190,20 +190,16 @@ private:
|
|||
};
|
||||
|
||||
protected:
|
||||
QFreetypeFace *freetype;
|
||||
int default_load_flags;
|
||||
|
||||
HintStyle default_hint_style;
|
||||
|
||||
bool embolden;
|
||||
|
||||
private:
|
||||
int loadFlags(QGlyphSet *set, int flags) const;
|
||||
|
||||
QFreetypeFace *freetype;
|
||||
bool embolden;
|
||||
FT_Matrix matrix;
|
||||
|
||||
mutable QGlyphSet defaultGlyphSet;
|
||||
|
||||
QFontEngine::FaceId face_id;
|
||||
|
||||
int xsize;
|
||||
|
|
|
@ -163,8 +163,6 @@ public:
|
|||
|
||||
QAtomicInt ref;
|
||||
QFontDef fontDef;
|
||||
int cache_cost; // amount of mem used in kb by the font
|
||||
int cache_count;
|
||||
int fsType;
|
||||
bool symbol;
|
||||
mutable HB_FontRec hbFont;
|
||||
|
|
|
@ -104,7 +104,6 @@ QFontEngineMultiFT::QFontEngineMultiFT(QFontEngine *fe, FcPattern *matchedPatter
|
|||
engines[0] = fe;
|
||||
engines.at(0)->ref.ref();
|
||||
fontDef = engines[0]->fontDef;
|
||||
cache_cost = 100;
|
||||
firstFontIndex = 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ public:
|
|||
: object_id(obj_id), noEmbed(false), fontEngine(fe), downloaded_glyphs(0), standard_font(false)
|
||||
{ fontEngine->ref.ref(); addGlyph(0); }
|
||||
~QFontSubset() {
|
||||
if (!fontEngine->ref.deref() && fontEngine->cache_count == 0)
|
||||
if (!fontEngine->ref.deref())
|
||||
delete fontEngine;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue