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(); }
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(); }
size_t FontCache::inactiveFontCount() { #if PLATFORM(IOS) FontLocker fontLocker; #endif unsigned count = 0; for (auto& font : cachedFonts().values()) { if (font->hasOneRef()) ++count; } return count; }
Ref<Font> FontCache::fontForPlatformData(const FontPlatformData& platformData) { #if PLATFORM(IOS) FontLocker fontLocker; #endif auto addResult = cachedFonts().add(platformData, nullptr); if (addResult.isNewEntry) addResult.iterator->value = Font::create(platformData); return *addResult.iterator->value; }
void FontCache::purgeInactiveFontDataIfNeeded() { bool underMemoryPressure = MemoryPressureHandler::singleton().isUnderMemoryPressure(); unsigned inactiveFontDataLimit = underMemoryPressure ? cMaxUnderMemoryPressureInactiveFontData : cMaxInactiveFontData; if (cachedFonts().size() < inactiveFontDataLimit) return; unsigned inactiveCount = inactiveFontCount(); if (inactiveCount <= inactiveFontDataLimit) return; unsigned targetFontDataLimit = underMemoryPressure ? cTargetUnderMemoryPressureInactiveFontData : cTargetInactiveFontData; purgeInactiveFontData(inactiveCount - targetFontDataLimit); }
size_t FontCache::fontCount() { return cachedFonts().size(); }