Rename FontDescriptionFontDataCacheKey to FontDescriptionKey
[WebKit-https.git] / Source / WebCore / platform / graphics / FontCache.cpp
index 28aa832..368c4b9 100644 (file)
 #include "config.h"
 #include "FontCache.h"
 
-#include "Font.h"
-#include "FontGlyphs.h"
+#include "FontCascade.h"
 #include "FontPlatformData.h"
 #include "FontSelector.h"
-#include "OpenTypeMathData.h"
+#include "MemoryPressureHandler.h"
 #include "WebKitFontFamilyNames.h"
 #include <wtf/HashMap.h>
 #include <wtf/ListHashSet.h>
 #include <wtf/NeverDestroyed.h>
 #include <wtf/StdLibExtras.h>
+#include <wtf/TemporaryChange.h>
 #include <wtf/text/AtomicStringHash.h>
 #include <wtf/text/StringHash.h>
 
 #endif
 
 #if PLATFORM(IOS)
-#include "MemoryPressureHandler.h"
 #include <wtf/Noncopyable.h>
 
 // FIXME: We may be able to simplify this code using C++11 threading primitives, including std::call_once().
-static pthread_mutex_t fontDataLock;
+static pthread_mutex_t fontLock;
 
 static void initFontCacheLockOnce()
 {
     pthread_mutexattr_t mutexAttribute;
     pthread_mutexattr_init(&mutexAttribute);
     pthread_mutexattr_settype(&mutexAttribute, PTHREAD_MUTEX_RECURSIVE);
-    pthread_mutex_init(&fontDataLock, &mutexAttribute);
+    pthread_mutex_init(&fontLock, &mutexAttribute);
     pthread_mutexattr_destroy(&mutexAttribute);
 }
 
@@ -71,13 +70,13 @@ public:
     FontLocker()
     {
         pthread_once(&initFontLockControl, initFontCacheLockOnce);
-        int lockcode = pthread_mutex_lock(&fontDataLock);
-        ASSERT_WITH_MESSAGE_UNUSED(lockcode, !lockcode, "fontDataLock lock failed with code:%d", lockcode);    
+        int lockcode = pthread_mutex_lock(&fontLock);
+        ASSERT_WITH_MESSAGE_UNUSED(lockcode, !lockcode, "fontLock lock failed with code:%d", lockcode);    
     }
     ~FontLocker()
     {
-        int lockcode = pthread_mutex_unlock(&fontDataLock);
-        ASSERT_WITH_MESSAGE_UNUSED(lockcode, !lockcode, "fontDataLock unlock failed with code:%d", lockcode);
+        int lockcode = pthread_mutex_unlock(&fontLock);
+        ASSERT_WITH_MESSAGE_UNUSED(lockcode, !lockcode, "fontLock unlock failed with code:%d", lockcode);
     }
 };
 #endif // PLATFORM(IOS)
@@ -86,15 +85,14 @@ using namespace WTF;
 
 namespace WebCore {
 
-// FIXME: We should return a reference instead of a pointer since we never return a nullptr.
-FontCache* fontCache()
+FontCache& FontCache::singleton()
 {
     static NeverDestroyed<FontCache> globalFontCache;
-    return &globalFontCache.get();
+    return globalFontCache;
 }
 
 FontCache::FontCache()
-    : m_purgePreventCount(0)
+    : m_purgeTimer(*this, &FontCache::purgeTimerFired)
 {
 }
 
@@ -115,22 +113,17 @@ public:
         return equalIgnoringCase(m_family, other.m_family) && m_fontDescriptionKey == other.m_fontDescriptionKey;
     }
 
-    FontDescriptionFontDataCacheKey m_fontDescriptionKey;
+    FontDescriptionKey m_fontDescriptionKey;
     AtomicString m_family;
 
 private:
     static unsigned hashTableDeletedSize() { return 0xFFFFFFFFU; }
 };
 
-inline unsigned computeHash(const FontPlatformDataCacheKey& fontKey)
-{
-    return pairIntHash(CaseFoldingHash::hash(fontKey.m_family), fontKey.m_fontDescriptionKey.computeHash());
-}
-
 struct FontPlatformDataCacheKeyHash {
-    static unsigned hash(const FontPlatformDataCacheKey& font)
+    static unsigned hash(const FontPlatformDataCacheKey& fontKey)
     {
-        return computeHash(font);
+        return pairIntHash(CaseFoldingHash::hash(fontKey.m_family), fontKey.m_fontDescriptionKey.computeHash());
     }
          
     static bool equal(const FontPlatformDataCacheKey& a, const FontPlatformDataCacheKey& b)
@@ -141,11 +134,13 @@ struct FontPlatformDataCacheKeyHash {
     static const bool safeToCompareToEmptyOrDeleted = true;
 };
 
-struct FontPlatformDataCacheKeyTraits : WTF::SimpleClassHashTraits<FontPlatformDataCacheKey> { };
+typedef HashMap<FontPlatformDataCacheKey, std::unique_ptr<FontPlatformData>, FontPlatformDataCacheKeyHash, WTF::SimpleClassHashTraits<FontPlatformDataCacheKey>> FontPlatformDataCache;
 
-typedef HashMap<FontPlatformDataCacheKey, OwnPtr<FontPlatformData>, FontPlatformDataCacheKeyHash, FontPlatformDataCacheKeyTraits> FontPlatformDataCache;
-
-static FontPlatformDataCache* gFontPlatformDataCache = 0;
+static FontPlatformDataCache& fontPlatformDataCache()
+{
+    static NeverDestroyed<FontPlatformDataCache> cache;
+    return cache;
+}
 
 static bool familyNameEqualIgnoringCase(const AtomicString& familyName, const char* reference, unsigned length)
 {
@@ -236,16 +231,17 @@ FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& fo
     const AtomicString& familyName = passedFamilyName;
 #endif
 
-    if (!gFontPlatformDataCache) {
-        gFontPlatformDataCache = new FontPlatformDataCache;
+    static bool initialized;
+    if (!initialized) {
         platformInit();
+        initialized = true;
     }
 
     FontPlatformDataCacheKey key(familyName, fontDescription);
 
-    FontPlatformDataCache::AddResult result = gFontPlatformDataCache->add(key, nullptr);
-    FontPlatformDataCache::iterator it = result.iterator;
-    if (result.isNewEntry) {
+    auto addResult = fontPlatformDataCache().add(key, nullptr);
+    FontPlatformDataCache::iterator it = addResult.iterator;
+    if (addResult.isNewEntry) {
         it->value = createFontPlatformData(fontDescription, familyName);
 
         if (!it->value && !checkingAlternateName) {
@@ -256,10 +252,10 @@ FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& fo
                 FontPlatformData* fontPlatformDataForAlternateName = getCachedFontPlatformData(fontDescription, alternateName, true);
                 // Lookup the key in the hash table again as the previous iterator may have
                 // been invalidated by the recursive call to getCachedFontPlatformData().
-                it = gFontPlatformDataCache->find(key);
-                ASSERT(it != gFontPlatformDataCache->end());
+                it = fontPlatformDataCache().find(key);
+                ASSERT(it != fontPlatformDataCache().end());
                 if (fontPlatformDataForAlternateName)
-                    it->value = adoptPtr(new FontPlatformData(*fontPlatformDataForAlternateName));
+                    it->value = std::make_unique<FontPlatformData>(*fontPlatformDataForAlternateName);
             }
         }
     }
@@ -267,7 +263,8 @@ FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& fo
     return it->value.get();
 }
 
-struct FontFileCacheKeyHash {
+#if ENABLE(OPENTYPE_VERTICAL)
+struct FontVerticalDataCacheKeyHash {
     static unsigned hash(const FontCache::FontFileKey& fontFileKey)
     {
         return PtrHash<const FontCache::FontFileKey*>::hash(&fontFileKey);
@@ -281,7 +278,7 @@ struct FontFileCacheKeyHash {
     static const bool safeToCompareToEmptyOrDeleted = true;
 };
 
-struct FontFileCacheKeyTraits : WTF::GenericHashTraits<FontCache::FontFileKey> {
+struct FontVerticalDataCacheKeyTraits : WTF::GenericHashTraits<FontCache::FontFileKey> {
     static const bool emptyValueIsZero = true;
     static const bool needsDestruction = true;
     static const FontCache::FontFileKey& emptyValue()
@@ -299,32 +296,9 @@ struct FontFileCacheKeyTraits : WTF::GenericHashTraits<FontCache::FontFileKey> {
     }
 };
 
-typedef HashMap<FontCache::FontFileKey, RefPtr<OpenTypeMathData>, FontFileCacheKeyHash, FontFileCacheKeyTraits> FontMathDataCache;
-
-static FontMathDataCache& fontMathDataCacheInstance()
-{
-    static NeverDestroyed<FontMathDataCache> fontMathDataCache;
-    return fontMathDataCache;
-}
-
-PassRefPtr<OpenTypeMathData> FontCache::getMathData(const FontFileKey& key, const FontPlatformData& fontData)
-{
-    FontMathDataCache& fontMathDataCache = fontMathDataCacheInstance();
-    FontMathDataCache::iterator result = fontMathDataCache.find(key);
-    if (result != fontMathDataCache.end())
-        return result.get()->value;
-
-    RefPtr<OpenTypeMathData> mathData = OpenTypeMathData::create(fontData);
-    if (!mathData->hasMathData())
-        mathData.clear();
-    fontMathDataCache.set(key, mathData);
-    return mathData;
-}
-
-#if ENABLE(OPENTYPE_VERTICAL)
-typedef HashMap<FontCache::FontFileKey, RefPtr<OpenTypeVerticalData>, FontFileCacheKeyHash, FontFileCacheKeyTraits> FontVerticalDataCache;
+typedef HashMap<FontCache::FontFileKey, RefPtr<OpenTypeVerticalData>, FontVerticalDataCacheKeyHash, FontVerticalDataCacheKeyTraits> FontVerticalDataCache;
 
-static FontVerticalDataCache& fontVerticalDataCacheInstance()
+FontVerticalDataCache& fontVerticalDataCacheInstance()
 {
     static NeverDestroyed<FontVerticalDataCache> fontVerticalDataCache;
     return fontVerticalDataCache;
@@ -339,7 +313,7 @@ PassRefPtr<OpenTypeVerticalData> FontCache::getVerticalData(const FontFileKey& k
 
     RefPtr<OpenTypeVerticalData> verticalData = OpenTypeVerticalData::create(platformData);
     if (!verticalData->isOpenType())
-        verticalData.clear();
+        verticalData = nullptr;
     fontVerticalDataCache.set(key, verticalData);
     return verticalData;
 }
@@ -361,7 +335,6 @@ struct FontDataCacheKeyHash {
 
 struct FontDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformData> {
     static const bool emptyValueIsZero = true;
-    static const bool needsDestruction = true;
     static const FontPlatformData& emptyValue()
     {
         static NeverDestroyed<FontPlatformData> key(0.f, false, false);
@@ -377,247 +350,146 @@ struct FontDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformData> {
     }
 };
 
-typedef HashMap<FontPlatformData, std::pair<RefPtr<SimpleFontData>, unsigned>, FontDataCacheKeyHash, FontDataCacheKeyTraits> FontDataCache;
+typedef HashMap<FontPlatformData, RefPtr<Font>, FontDataCacheKeyHash, FontDataCacheKeyTraits> FontDataCache;
+
+static FontDataCache& cachedFonts()
+{
+    static NeverDestroyed<FontDataCache> cache;
+    return cache;
+}
 
-static FontDataCache* gFontDataCache = 0;
 
 #if PLATFORM(IOS)
-const int cMaxInactiveFontData = 120;
-const int cTargetInactiveFontData = 100;
-const int cMaxUnderMemoryPressureInactiveFontData = 50;
-const int cTargetUnderMemoryPressureInactiveFontData = 30;
+const unsigned cMaxInactiveFontData = 120;
+const unsigned cTargetInactiveFontData = 100;
 #else
-const int cMaxInactiveFontData = 225;
-const int cTargetInactiveFontData = 200;
+const unsigned cMaxInactiveFontData = 225;
+const unsigned cTargetInactiveFontData = 200;
 #endif
-static ListHashSet<RefPtr<SimpleFontData>>* gInactiveFontData = 0;
 
-PassRefPtr<SimpleFontData> FontCache::getCachedFontData(const FontDescription& fontDescription, const AtomicString& family, bool checkingAlternateName, ShouldRetain shouldRetain)
+const unsigned cMaxUnderMemoryPressureInactiveFontData = 50;
+const unsigned cTargetUnderMemoryPressureInactiveFontData = 30;
+
+RefPtr<Font> FontCache::fontForFamily(const FontDescription& fontDescription, const AtomicString& family, bool checkingAlternateName)
 {
+    if (!m_purgeTimer.isActive())
+        m_purgeTimer.startOneShot(std::chrono::milliseconds::zero());
+
     FontPlatformData* platformData = getCachedFontPlatformData(fontDescription, family, checkingAlternateName);
     if (!platformData)
-        return 0;
+        return nullptr;
 
-    return getCachedFontData(platformData, shouldRetain);
+    return fontForPlatformData(*platformData);
 }
 
-PassRefPtr<SimpleFontData> FontCache::getCachedFontData(const FontPlatformData* platformData, ShouldRetain shouldRetain)
+Ref<Font> FontCache::fontForPlatformData(const FontPlatformData& platformData)
 {
-    if (!platformData)
-        return 0;
-
-#if !ASSERT_DISABLED
-    if (shouldRetain == DoNotRetain)
-        ASSERT(m_purgePreventCount);
-#endif
-
 #if PLATFORM(IOS)
     FontLocker fontLocker;
 #endif
     
-    if (!gFontDataCache) {
-        gFontDataCache = new FontDataCache;
-        gInactiveFontData = new ListHashSet<RefPtr<SimpleFontData>>;
-    }
-
-    FontDataCache::iterator result = gFontDataCache->find(*platformData);
-    if (result == gFontDataCache->end()) {
-        std::pair<RefPtr<SimpleFontData>, unsigned> newValue(SimpleFontData::create(*platformData), shouldRetain == Retain ? 1 : 0);
-        gFontDataCache->set(*platformData, newValue);
-        if (shouldRetain == DoNotRetain)
-            gInactiveFontData->add(newValue.first);
-        return newValue.first.release();
-    }
-
-    if (!result.get()->value.second) {
-        ASSERT(gInactiveFontData->contains(result.get()->value.first));
-        gInactiveFontData->remove(result.get()->value.first);
-    }
+    auto addResult = cachedFonts().add(platformData, nullptr);
+    if (addResult.isNewEntry)
+        addResult.iterator->value = Font::create(platformData);
 
-    if (shouldRetain == Retain)
-        result.get()->value.second++;
-    else if (!result.get()->value.second) {
-        // If shouldRetain is DoNotRetain and count is 0, we want to remove the fontData from 
-        // gInactiveFontData (above) and re-add here to update LRU position.
-        gInactiveFontData->add(result.get()->value.first);
-    }
-
-    return result.get()->value.first;
+    return *addResult.iterator->value;
 }
 
-SimpleFontData* FontCache::getNonRetainedLastResortFallbackFont(const FontDescription& fontDescription)
+void FontCache::purgeTimerFired()
 {
-    return getLastResortFallbackFont(fontDescription, DoNotRetain).leakRef();
+    purgeInactiveFontDataIfNeeded();
 }
 
-void FontCache::releaseFontData(const SimpleFontData* fontData)
+void FontCache::purgeInactiveFontDataIfNeeded()
 {
-    ASSERT(gFontDataCache);
-    ASSERT(!fontData->isCustomFont());
+    bool underMemoryPressure = MemoryPressureHandler::singleton().isUnderMemoryPressure();
+    unsigned inactiveFontDataLimit = underMemoryPressure ? cMaxUnderMemoryPressureInactiveFontData : cMaxInactiveFontData;
 
-#if PLATFORM(IOS)
-    FontLocker fontLocker;
-#endif
-    
-    FontDataCache::iterator it = gFontDataCache->find(fontData->platformData());
-    ASSERT(it != gFontDataCache->end());
-    if (it == gFontDataCache->end())
+    if (cachedFonts().size() < inactiveFontDataLimit)
+        return;
+    unsigned inactiveCount = inactiveFontCount();
+    if (inactiveCount <= inactiveFontDataLimit)
         return;
 
-    ASSERT(it->value.second);
-    if (!--it->value.second)
-        gInactiveFontData->add(it->value.first);
+    unsigned targetFontDataLimit = underMemoryPressure ? cTargetUnderMemoryPressureInactiveFontData : cTargetInactiveFontData;
+    purgeInactiveFontData(inactiveCount - targetFontDataLimit);
 }
 
-void FontCache::purgeInactiveFontDataIfNeeded()
+void FontCache::purgeInactiveFontData(unsigned purgeCount)
 {
-#if PLATFORM(IOS)
-    bool underMemoryPressure = memoryPressureHandler().hasReceivedMemoryPressure();
-    int inactiveFontDataLimit = underMemoryPressure ? cMaxUnderMemoryPressureInactiveFontData : cMaxInactiveFontData;
-    int targetFontDataLimit = underMemoryPressure ? cTargetUnderMemoryPressureInactiveFontData : cTargetInactiveFontData;
-
-    if (gInactiveFontData && !m_purgePreventCount && gInactiveFontData->size() > inactiveFontDataLimit)
-        purgeInactiveFontData(gInactiveFontData->size() - targetFontDataLimit);
-#else
-    if (gInactiveFontData && !m_purgePreventCount && gInactiveFontData->size() > cMaxInactiveFontData)
-        purgeInactiveFontData(gInactiveFontData->size() - cTargetInactiveFontData);
-#endif
-}
-
-void FontCache::purgeInactiveFontData(int count)
-{
-    pruneUnreferencedEntriesFromFontGlyphsCache();
-
-    if (!gInactiveFontData || m_purgePreventCount)
-        return;
-
-    static bool isPurging;  // Guard against reentry when e.g. a deleted FontData releases its small caps FontData.
-    if (isPurging)
-        return;
-
-    isPurging = true;
+    pruneUnreferencedEntriesFromFontCascadeCache();
+    pruneSystemFallbackFonts();
 
 #if PLATFORM(IOS)
     FontLocker fontLocker;
 #endif
 
-    Vector<RefPtr<SimpleFontData>, 20> fontDataToDelete;
-    ListHashSet<RefPtr<SimpleFontData>>::iterator end = gInactiveFontData->end();
-    ListHashSet<RefPtr<SimpleFontData>>::iterator it = gInactiveFontData->begin();
-    for (int i = 0; i < count && it != end; ++it, ++i) {
-        RefPtr<SimpleFontData>& fontData = *it.get();
-        gFontDataCache->remove(fontData->platformData());
-        // We should not delete SimpleFontData here because deletion can modify gInactiveFontData. See http://trac.webkit.org/changeset/44011
-        fontDataToDelete.append(fontData);
-    }
-
-    if (it == end) {
-        // Removed everything
-        gInactiveFontData->clear();
-    } else {
-        for (int i = 0; i < count; ++i)
-            gInactiveFontData->remove(gInactiveFontData->begin());
-    }
-
-    fontDataToDelete.clear();
-
-    if (gFontPlatformDataCache) {
-        Vector<FontPlatformDataCacheKey> keysToRemove;
-        keysToRemove.reserveInitialCapacity(gFontPlatformDataCache->size());
-        FontPlatformDataCache::iterator platformDataEnd = gFontPlatformDataCache->end();
-        for (FontPlatformDataCache::iterator platformData = gFontPlatformDataCache->begin(); platformData != platformDataEnd; ++platformData) {
-            if (platformData->value && !gFontDataCache->contains(*platformData->value))
-                keysToRemove.append(platformData->key);
+    while (purgeCount) {
+        Vector<RefPtr<Font>, 20> fontsToDelete;
+        for (auto& font : cachedFonts().values()) {
+            if (!font->hasOneRef())
+                continue;
+            fontsToDelete.append(WTF::move(font));
+            if (!--purgeCount)
+                break;
         }
-        
-        size_t keysToRemoveCount = keysToRemove.size();
-        for (size_t i = 0; i < keysToRemoveCount; ++i)
-            gFontPlatformDataCache->remove(keysToRemove[i]);
+        // Fonts may ref other fonts so we loop until there are no changes.
+        if (fontsToDelete.isEmpty())
+            break;
+        for (auto& font : fontsToDelete)
+            cachedFonts().remove(font->platformData());
+    };
+
+    Vector<FontPlatformDataCacheKey> keysToRemove;
+    keysToRemove.reserveInitialCapacity(fontPlatformDataCache().size());
+    for (auto& entry : fontPlatformDataCache()) {
+        if (entry.value && !cachedFonts().contains(*entry.value))
+            keysToRemove.append(entry.key);
     }
+    for (auto key : keysToRemove)
+        fontPlatformDataCache().remove(key);
 
 #if ENABLE(OPENTYPE_VERTICAL)
     FontVerticalDataCache& fontVerticalDataCache = fontVerticalDataCacheInstance();
     if (!fontVerticalDataCache.isEmpty()) {
         // Mark & sweep unused verticalData
-        FontVerticalDataCache::iterator verticalDataEnd = fontVerticalDataCache.end();
-        for (FontVerticalDataCache::iterator verticalData = fontVerticalDataCache.begin(); verticalData != verticalDataEnd; ++verticalData) {
-            if (verticalData->value)
-                verticalData->value->m_inFontCache = false;
+        for (auto& verticalData : fontVerticalDataCache.values()) {
+            if (verticalData)
+                verticalData->m_inFontCache = false;
         }
-        FontDataCache::iterator fontDataEnd = gFontDataCache->end();
-        for (FontDataCache::iterator fontData = gFontDataCache->begin(); fontData != fontDataEnd; ++fontData) {
-            OpenTypeVerticalData* verticalData = const_cast<OpenTypeVerticalData*>(fontData->value.first->verticalData());
+        for (auto& font : cachedFonts().values()) {
+            auto* verticalData = const_cast<OpenTypeVerticalData*>(font->verticalData());
             if (verticalData)
                 verticalData->m_inFontCache = true;
         }
         Vector<FontFileKey> keysToRemove;
         keysToRemove.reserveInitialCapacity(fontVerticalDataCache.size());
-        for (FontVerticalDataCache::iterator verticalData = fontVerticalDataCache.begin(); verticalData != verticalDataEnd; ++verticalData) {
-            if (!verticalData->value || !verticalData->value->m_inFontCache)
-                keysToRemove.append(verticalData->key);
+        for (auto& it : fontVerticalDataCache) {
+            if (!it.value || !it.value->m_inFontCache)
+                keysToRemove.append(it.key);
         }
-        for (size_t i = 0, count = keysToRemove.size(); i < count; ++i)
-            fontVerticalDataCache.take(keysToRemove[i]);
+        for (auto& key : keysToRemove)
+            fontVerticalDataCache.remove(key);
     }
 #endif
-
-    isPurging = false;
 }
 
-size_t FontCache::fontDataCount()
+size_t FontCache::fontCount()
 {
-    if (gFontDataCache)
-        return gFontDataCache->size();
-    return 0;
+    return cachedFonts().size();
 }
 
-size_t FontCache::inactiveFontDataCount()
+size_t FontCache::inactiveFontCount()
 {
-    if (gInactiveFontData)
-        return gInactiveFontData->size();
-    return 0;
-}
-
-PassRefPtr<FontData> FontCache::getFontData(const FontDescription& description, int& familyIndex, FontSelector* fontSelector)
-{
-    ASSERT(familyIndex != cAllFamiliesScanned);
-    RefPtr<FontData> result;
-
-    bool isFirst = !familyIndex;
-    int familyCount = description.familyCount();
-    for (;familyIndex < familyCount && !result; ++familyIndex) {
-        const AtomicString& family = description.familyAt(familyIndex);
-        if (family.isEmpty())
-            continue;
-        if (fontSelector)
-            result = fontSelector->getFontData(description, family);
-        if (!result)
-            result = getCachedFontData(description, family);
-    }
-    if (familyIndex == familyCount)
-        familyIndex = cAllFamiliesScanned;
-
-#if PLATFORM(COCOA)
-    if (!result) {
-        // We didn't find a font. Try to find a similar font using our own specific knowledge about our platform.
-        // For example on OS X, we know to map any families containing the words Arabic, Pashto, or Urdu to the
-        // Geeza Pro font.
-        result = similarFontPlatformData(description);
-    }
+#if PLATFORM(IOS)
+    FontLocker fontLocker;
 #endif
-
-    if (!result && isFirst) {
-        // If it's the primary font that we couldn't find, we try the following. In all other cases, we will
-        // just use per-character system fallback.
-        if (fontSelector) {
-            // Try the user's preferred standard font.
-            if (RefPtr<FontData> data = fontSelector->getFontData(description, standardFamily))
-                return data.release();
-        }
-        // Still no result.  Hand back our last resort fallback font.
-        result = getLastResortFallbackFont(description);
+    unsigned count = 0;
+    for (auto& font : cachedFonts().values()) {
+        if (font->hasOneRef())
+            ++count;
     }
-    return result.release();
+    return count;
 }
 
 static HashSet<FontSelector*>* gClients;
@@ -649,13 +521,12 @@ unsigned short FontCache::generation()
 void FontCache::invalidate()
 {
     if (!gClients) {
-        ASSERT(!gFontPlatformDataCache);
+        ASSERT(fontPlatformDataCache().isEmpty());
         return;
     }
 
-    if (gFontPlatformDataCache)
-        gFontPlatformDataCache->clear();
-    invalidateFontGlyphsCache();
+    fontPlatformDataCache().clear();
+    invalidateFontCascadeCache();
 
     gGeneration++;
 
@@ -670,4 +541,11 @@ void FontCache::invalidate()
     purgeInactiveFontData();
 }
 
+#if !PLATFORM(COCOA)
+RefPtr<Font> FontCache::similarFont(const FontDescription&)
+{
+    return nullptr;
+}
+#endif
+
 } // namespace WebCore