void FontCache::invalidate() { if (!gClients) { ASSERT(fontPlatformDataCache().isEmpty()); return; } fontPlatformDataCache().clear(); #if ENABLE(OPENTYPE_VERTICAL) fontVerticalDataCache().clear(); #endif invalidateFontCascadeCache(); gGeneration++; Vector<Ref<FontSelector>> clients; clients.reserveInitialCapacity(gClients->size()); for (auto it = gClients->begin(), end = gClients->end(); it != end; ++it) clients.uncheckedAppend(**it); for (unsigned i = 0; i < clients.size(); ++i) clients[i]->fontCacheInvalidated(); purgeInactiveFontData(); }
void FontCache::purgeInactiveFontData(unsigned purgeCount) { pruneUnreferencedEntriesFromFontCascadeCache(); pruneSystemFallbackFonts(); #if PLATFORM(IOS) FontLocker fontLocker; #endif while (purgeCount) { Vector<RefPtr<Font>, 20> fontsToDelete; for (auto& font : cachedFonts().values()) { if (!font->hasOneRef()) continue; fontsToDelete.append(WTF::move(font)); if (!--purgeCount) break; } // 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 for (auto& verticalData : fontVerticalDataCache.values()) { if (verticalData) verticalData->m_inFontCache = false; } 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 (auto& it : fontVerticalDataCache) { if (!it.value || !it.value->m_inFontCache) keysToRemove.append(it.key); } for (auto& key : keysToRemove) fontVerticalDataCache.remove(key); } #endif platformPurgeInactiveFontData(); }
FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& fontDescription, const AtomicString& passedFamilyName, bool checkingAlternateName) { #if PLATFORM(IOS) FontLocker fontLocker; #endif #if OS(WINDOWS) && ENABLE(OPENTYPE_VERTICAL) // Leading "@" in the font name enables Windows vertical flow flag for the font. // Because we do vertical flow by ourselves, we don't want to use the Windows feature. // IE disregards "@" regardless of the orientatoin, so we follow the behavior. const AtomicString& familyName = (passedFamilyName.isEmpty() || passedFamilyName[0] != '@') ? passedFamilyName : AtomicString(passedFamilyName.impl()->substring(1)); #else const AtomicString& familyName = passedFamilyName; #endif static bool initialized; if (!initialized) { platformInit(); initialized = true; } FontPlatformDataCacheKey key(familyName, fontDescription); auto addResult = fontPlatformDataCache().add(key, nullptr); FontPlatformDataCache::iterator it = addResult.iterator; if (addResult.isNewEntry) { it->value = createFontPlatformData(fontDescription, familyName); if (!it->value && !checkingAlternateName) { // We were unable to find a font. We have a small set of fonts that we alias to other names, // e.g., Arial/Helvetica, Courier/Courier New, etc. Try looking up the font under the aliased name. const AtomicString alternateName = alternateFamilyName(familyName); if (!alternateName.isNull()) { 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 = fontPlatformDataCache().find(key); ASSERT(it != fontPlatformDataCache().end()); if (fontPlatformDataForAlternateName) it->value = std::make_unique<FontPlatformData>(*fontPlatformDataForAlternateName); } } } return it->value.get(); }
void FontCache::purgeInactiveFontData(unsigned purgeCount) { pruneUnreferencedEntriesFromFontCascadeCache(); pruneSystemFallbackFonts(); #if PLATFORM(IOS) FontLocker fontLocker; #endif while (purgeCount) { Vector<RefPtr<Font>, 20> fontsToDelete; for (auto& font : cachedFonts().values()) { if (!font->hasOneRef()) continue; fontsToDelete.append(WTFMove(font)); if (!--purgeCount) break; } // Fonts may ref other fonts so we loop until there are no changes. if (fontsToDelete.isEmpty()) break; for (auto& font : fontsToDelete) { bool success = cachedFonts().remove(font->platformData()); ASSERT_UNUSED(success, success); #if ENABLE(OPENTYPE_VERTICAL) fontVerticalDataCache().remove(font->platformData()); #endif } }; 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); platformPurgeInactiveFontData(); }