summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/webkit/WebCore/platform/graphics/qt/FontCacheQt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/webkit/WebCore/platform/graphics/qt/FontCacheQt.cpp')
-rw-r--r--src/3rdparty/webkit/WebCore/platform/graphics/qt/FontCacheQt.cpp230
1 files changed, 208 insertions, 22 deletions
diff --git a/src/3rdparty/webkit/WebCore/platform/graphics/qt/FontCacheQt.cpp b/src/3rdparty/webkit/WebCore/platform/graphics/qt/FontCacheQt.cpp
index 668912ece..5d29389c9 100644
--- a/src/3rdparty/webkit/WebCore/platform/graphics/qt/FontCacheQt.cpp
+++ b/src/3rdparty/webkit/WebCore/platform/graphics/qt/FontCacheQt.cpp
@@ -1,6 +1,8 @@
/*
Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
Copyright (C) 2008 Holger Hans Peter Freyther
+ Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -26,10 +28,13 @@
#include "FontDescription.h"
#include "FontPlatformData.h"
#include "Font.h"
+#include "PlatformString.h"
#include "StringHash.h"
+#include <utility>
+#include <wtf/ListHashSet.h>
#include <wtf/StdLibExtras.h>
-#include <QHash>
+using namespace WTF;
namespace WebCore {
@@ -47,36 +52,173 @@ void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigne
{
}
-typedef QHash<FontDescription, FontPlatformData*> FontPlatformDataCache;
+// This type must be consistent with FontPlatformData's ctor - the one which
+// gets FontDescription as it's parameter.
+class FontPlatformDataCacheKey {
+public:
+ FontPlatformDataCacheKey(const FontDescription& description)
+ : m_familyName()
+ , m_bold(false)
+ , m_size(description.computedPixelSize())
+ , m_italic(description.italic())
+ , m_smallCaps(description.smallCaps())
+ , m_hash(0)
+ {
+ // FIXME: Map all FontWeight values to QFont weights in FontPlatformData's ctor and follow it here
+ if (FontPlatformData::toQFontWeight(description.weight()) > QFont::Normal)
+ m_bold = true;
-// using Q_GLOBAL_STATIC leads to crash. TODO investigate the way to fix this.
-static FontPlatformDataCache* gFontPlatformDataCache;
+ const FontFamily* family = &description.family();
+ while (family) {
+ m_familyName.append(family->family());
+ family = family->next();
+ if (family)
+ m_familyName.append(',');
+ }
-uint qHash(const FontDescription& key)
-{
- uint value = CaseFoldingHash::hash(key.family().family());
- value ^= key.computedPixelSize();
- value ^= static_cast<int>(key.weight());
- return value;
-}
+ computeHash();
+ }
+
+ FontPlatformDataCacheKey(const FontPlatformData& fontData)
+ : m_familyName(static_cast<String>(fontData.family()))
+ , m_size(fontData.pixelSize())
+ , m_bold(fontData.bold())
+ , m_italic(fontData.italic())
+ , m_smallCaps(fontData.smallCaps())
+ , m_hash(0)
+ {
+ computeHash();
+ }
+
+ FontPlatformDataCacheKey(HashTableDeletedValueType) : m_size(hashTableDeletedSize()) { }
+ bool isHashTableDeletedValue() const { return m_size == hashTableDeletedSize(); }
+
+ enum HashTableEmptyValueType { HashTableEmptyValue };
+
+ FontPlatformDataCacheKey(HashTableEmptyValueType)
+ : m_familyName()
+ , m_size(0)
+ , m_bold(false)
+ , m_italic(false)
+ , m_smallCaps(false)
+ , m_hash(0)
+ {
+ }
+
+ bool operator==(const FontPlatformDataCacheKey& other) const
+ {
+ if (m_hash != other.m_hash)
+ return false;
+
+ return equalIgnoringCase(m_familyName, other.m_familyName) && m_size == other.m_size &&
+ m_bold == other.m_bold && m_italic == other.m_italic && m_smallCaps == other.m_smallCaps;
+ }
+
+ unsigned hash() const
+ {
+ return m_hash;
+ }
+
+ void computeHash()
+ {
+ unsigned hashCodes[] = {
+ CaseFoldingHash::hash(m_familyName),
+ m_size | static_cast<unsigned>(m_bold << sizeof(unsigned) * 8 - 1)
+ | static_cast<unsigned>(m_italic) << sizeof(unsigned) *8 - 2
+ | static_cast<unsigned>(m_smallCaps) << sizeof(unsigned) * 8 - 3
+ };
+ m_hash = StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar));
+ }
+
+private:
+ String m_familyName;
+ int m_size;
+ bool m_bold;
+ bool m_italic;
+ bool m_smallCaps;
+ unsigned m_hash;
+
+ static unsigned hashTableDeletedSize() { return 0xFFFFFFFFU; }
+};
+
+struct FontPlatformDataCacheKeyHash {
+ static unsigned hash(const FontPlatformDataCacheKey& key)
+ {
+ return key.hash();
+ }
+
+ static bool equal(const FontPlatformDataCacheKey& a, const FontPlatformDataCacheKey& b)
+ {
+ return a == b;
+ }
+
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+struct FontPlatformDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformDataCacheKey> {
+ static const bool needsDestruction = true;
+ static const FontPlatformDataCacheKey& emptyValue()
+ {
+ DEFINE_STATIC_LOCAL(FontPlatformDataCacheKey, key, (FontPlatformDataCacheKey::HashTableEmptyValue));
+ return key;
+ }
+ static void constructDeletedValue(FontPlatformDataCacheKey& slot)
+ {
+ new (&slot) FontPlatformDataCacheKey(HashTableDeletedValue);
+ }
+ static bool isDeletedValue(const FontPlatformDataCacheKey& value)
+ {
+ return value.isHashTableDeletedValue();
+ }
+};
+
+typedef HashMap<FontPlatformDataCacheKey, FontPlatformData*, FontPlatformDataCacheKeyHash, FontPlatformDataCacheKeyTraits> FontPlatformDataCache;
+
+// using Q_GLOBAL_STATIC leads to crash. TODO investigate the way to fix this.
+static FontPlatformDataCache* gFontPlatformDataCache = 0;
FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& description, const AtomicString& family, bool checkingAlternateName)
{
if (!gFontPlatformDataCache)
gFontPlatformDataCache = new FontPlatformDataCache;
- FontPlatformData* fontData = gFontPlatformDataCache->value(description, 0);
- if (!fontData) {
- fontData = new FontPlatformData(description);
- gFontPlatformDataCache->insert(description, fontData);
+ FontPlatformDataCacheKey key(description);
+ FontPlatformData* platformData = gFontPlatformDataCache->get(key);
+ if (!platformData) {
+ platformData = new FontPlatformData(description);
+ gFontPlatformDataCache->add(key, platformData);
}
-
- return fontData;
+ return platformData;
}
-SimpleFontData* FontCache::getCachedFontData(const FontPlatformData*)
+typedef HashMap<FontPlatformDataCacheKey, std::pair<SimpleFontData*, unsigned>, FontPlatformDataCacheKeyHash, FontPlatformDataCacheKeyTraits> FontDataCache;
+
+static FontDataCache* gFontDataCache = 0;
+
+static const int cMaxInactiveFontData = 40;
+static const int cTargetInactiveFontData = 32;
+
+static ListHashSet<const SimpleFontData*>* gInactiveFontDataSet = 0;
+
+SimpleFontData* FontCache::getCachedFontData(const FontPlatformData* fontPlatformData)
{
- return 0;
+ if (!gFontDataCache) {
+ gFontDataCache = new FontDataCache;
+ gInactiveFontDataSet = new ListHashSet<const SimpleFontData*>;
+ }
+
+ FontPlatformDataCacheKey key(*fontPlatformData);
+ FontDataCache::iterator it = gFontDataCache->find(key);
+ if (it == gFontDataCache->end()) {
+ SimpleFontData* fontData = new SimpleFontData(*fontPlatformData);
+ gFontDataCache->add(key, std::pair<SimpleFontData*, unsigned>(fontData, 1));
+ return fontData;
+ }
+ if (!it->second.second++) {
+ ASSERT(gInactiveFontDataSet->contains(it->second.first));
+ gInactiveFontDataSet->remove(it->second.first);
+ }
+ return it->second.first;
}
FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription&)
@@ -84,8 +226,52 @@ FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription&)
return 0;
}
-void FontCache::releaseFontData(const WebCore::SimpleFontData*)
+void FontCache::releaseFontData(const WebCore::SimpleFontData* fontData)
{
+ ASSERT(gFontDataCache);
+ ASSERT(!fontData->isCustomFont());
+
+ FontPlatformDataCacheKey key(fontData->platformData());
+ FontDataCache::iterator it = gFontDataCache->find(key);
+ ASSERT(it != gFontDataCache->end());
+ if (!--it->second.second) {
+ gInactiveFontDataSet->add(it->second.first);
+ if (gInactiveFontDataSet->size() > cMaxInactiveFontData)
+ purgeInactiveFontData(gInactiveFontDataSet->size() - cTargetInactiveFontData);
+ }
+}
+
+void FontCache::purgeInactiveFontData(int count)
+{
+ static bool isPurging; // Guard against reentry when e.g. a deleted FontData releases its small caps FontData.
+ if (isPurging)
+ return;
+
+ isPurging = true;
+
+ ListHashSet<const SimpleFontData*>::iterator it = gInactiveFontDataSet->begin();
+ ListHashSet<const SimpleFontData*>::iterator end = gInactiveFontDataSet->end();
+ for (int i = 0; i < count && it != end; ++i, ++it) {
+ FontPlatformDataCacheKey key = (*it)->platformData();
+ pair<SimpleFontData*, unsigned> fontDataPair = gFontDataCache->take(key);
+ ASSERT(fontDataPair.first != 0);
+ ASSERT(!fontDataPair.second);
+ delete fontDataPair.first;
+
+ FontPlatformData* platformData = gFontPlatformDataCache->take(key);
+ if (platformData)
+ delete platformData;
+ }
+
+ if (it == end) {
+ // Removed everything
+ gInactiveFontDataSet->clear();
+ } else {
+ for (int i = 0; i < count; ++i)
+ gInactiveFontDataSet->remove(gInactiveFontDataSet->begin());
+ }
+
+ isPurging = false;
}
void FontCache::addClient(FontSelector*)
@@ -98,10 +284,10 @@ void FontCache::removeClient(FontSelector*)
void FontCache::invalidate()
{
- if (!gFontPlatformDataCache)
+ if (!gFontPlatformDataCache || !gFontDataCache)
return;
- gFontPlatformDataCache->clear();
+ purgeInactiveFontData();
}
} // namespace WebCore