diff options
Diffstat (limited to 'WebCore/platform/graphics/qt/FontCacheQt.cpp')
-rw-r--r-- | WebCore/platform/graphics/qt/FontCacheQt.cpp | 230 |
1 files changed, 208 insertions, 22 deletions
diff --git a/WebCore/platform/graphics/qt/FontCacheQt.cpp b/WebCore/platform/graphics/qt/FontCacheQt.cpp index 668912e..5d29389 100644 --- a/WebCore/platform/graphics/qt/FontCacheQt.cpp +++ b/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 |